mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-31 05:54:38 -04:00
(Daily sync) Password reset pages & client portal rework (#3492)
* Dependency clearing * Tailwind & templates cleanup * Password reset pages & more features: - New $this->render() method - Password reset pages - Tailwind CSS scaffold - New styles for buttons, inputs, alerts - Changed to shorthand syntax for language file (en) - Added app.css and app.js which will be main endpoint - Added new 'theme' field inside of ninja.php - Scaffold for 'ninja2020' theme: both client and global theme - Ignoring local builds of assets, until purgeCSS is there - Overall cleanup * Switch back default template to 'default' * Remove app.css build * Fix Codacy * Fix Codacy 'doublequote' issues
This commit is contained in:
parent
648cd73bec
commit
aad9f81e93
4
.gitignore
vendored
4
.gitignore
vendored
@ -26,3 +26,7 @@ public/mix-manifest.json
|
|||||||
|
|
||||||
# Ignore local migrations
|
# Ignore local migrations
|
||||||
storage/migrations
|
storage/migrations
|
||||||
|
|
||||||
|
# Ignore Tailwind & Javascript build file >2mb without PurgeCSS (development-only)
|
||||||
|
public/css/app.css
|
||||||
|
public/js/app.js
|
||||||
|
@ -90,7 +90,6 @@ class ForgotPasswordController extends Controller
|
|||||||
* example="Unable to send password reset link",
|
* example="Unable to send password reset link",
|
||||||
* ),
|
* ),
|
||||||
* ),
|
* ),
|
||||||
|
|
||||||
* ),
|
* ),
|
||||||
* @OA\Response(
|
* @OA\Response(
|
||||||
* response="default",
|
* response="default",
|
||||||
@ -110,9 +109,20 @@ class ForgotPasswordController extends Controller
|
|||||||
$response = $this->broker()->sendResetLink(
|
$response = $this->broker()->sendResetLink(
|
||||||
$this->credentials($request)
|
$this->credentials($request)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if ($request->ajax()) {
|
||||||
|
return $response == Password::RESET_LINK_SENT
|
||||||
|
? response()->json(['message' => 'Reset link sent to your email.', 'status' => true], 201)
|
||||||
|
: response()->json(['message' => 'Email not found', 'status' => false], 401);
|
||||||
|
}
|
||||||
|
|
||||||
return $response == Password::RESET_LINK_SENT
|
return $response == Password::RESET_LINK_SENT
|
||||||
? response()->json(['message' => 'Reset link sent to your email.', 'status' => true], 201)
|
? $this->sendResetLinkResponse($request, $response)
|
||||||
: response()->json(['message' => 'Email not found', 'status' => false], 401);
|
: $this->sendResetLinkFailedResponse($request, $response);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function showLinkRequestForm()
|
||||||
|
{
|
||||||
|
return $this->render('auth.passwords.request', ['root' => 'themes']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,8 @@ namespace App\Http\Controllers\Auth;
|
|||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Password;
|
||||||
|
|
||||||
class ResetPasswordController extends Controller
|
class ResetPasswordController extends Controller
|
||||||
{
|
{
|
||||||
@ -34,7 +36,7 @@ class ResetPasswordController extends Controller
|
|||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $redirectTo = '/dashboard';
|
protected $redirectTo = '/';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new controller instance.
|
* Create a new controller instance.
|
||||||
@ -45,4 +47,47 @@ class ResetPasswordController extends Controller
|
|||||||
{
|
{
|
||||||
$this->middleware('guest');
|
$this->middleware('guest');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function showResetForm(Request $request, $token = null)
|
||||||
|
{
|
||||||
|
return $this->render('auth.passwords.reset', ['root' => 'themes', 'token' => $token]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the given user's password.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
|
public function reset(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate($this->rules(), $this->validationErrorMessages());
|
||||||
|
|
||||||
|
// Here we will attempt to reset the user's password. If it is successful we
|
||||||
|
// will update the password on an actual user model and persist it to the
|
||||||
|
// database. Otherwise we will parse the error and return the response.
|
||||||
|
$response = $this->broker()->reset(
|
||||||
|
$this->credentials($request), function ($user, $password) {
|
||||||
|
$this->resetPassword($user, $password);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Added this because it collides the session between
|
||||||
|
// client & main portal giving unlimited redirects.
|
||||||
|
auth()->logout();
|
||||||
|
|
||||||
|
// If the password was successfully reset, we will redirect the user back to
|
||||||
|
// the application's home authenticated view. If there is an error we can
|
||||||
|
// redirect them back to where they came from with their error message.
|
||||||
|
return $response == Password::PASSWORD_RESET
|
||||||
|
? $this->sendResetResponse($request, $response)
|
||||||
|
: $this->sendResetFailedResponse($request, $response);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function afterReset()
|
||||||
|
{
|
||||||
|
auth()->logout();
|
||||||
|
|
||||||
|
return redirect('/');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,11 +20,11 @@ class DashboardController extends Controller
|
|||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
return view('portal.default.dashboard.index');
|
return view('dashboard.index');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,4 +20,23 @@ use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
|||||||
class Controller extends BaseController
|
class Controller extends BaseController
|
||||||
{
|
{
|
||||||
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
|
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $path
|
||||||
|
* @param array $options
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||||
|
*/
|
||||||
|
public function render(string $path, array $options = [])
|
||||||
|
{
|
||||||
|
$theme = array_key_exists('theme', $options) ? $options['theme'] : 'ninja2020';
|
||||||
|
|
||||||
|
if (array_key_exists('root', $options)) {
|
||||||
|
return view(
|
||||||
|
sprintf('%s.%s.%s', $options['root'], $theme, $path)
|
||||||
|
, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
return view("portal.$theme.$path", $options);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,5 +128,8 @@ return [
|
|||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'themes' => [
|
||||||
|
'global' => 'ninja2020',
|
||||||
|
'portal' => 'ninja2020',
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
9443
package-lock.json
generated
Normal file
9443
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
54
package.json
54
package.json
@ -1,30 +1,28 @@
|
|||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "npm run development",
|
"dev": "npm run development",
|
||||||
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
|
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
|
||||||
"watch": "npm run development -- --watch",
|
"watch": "npm run development -- --watch",
|
||||||
"watch-poll": "npm run watch -- --watch-poll",
|
"watch-poll": "npm run watch -- --watch-poll",
|
||||||
"hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
|
"hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
|
||||||
"prod": "npm run production",
|
"prod": "npm run production",
|
||||||
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
|
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
|
||||||
},
|
},
|
||||||
"devDependencies": {},
|
"devDependencies": {
|
||||||
"dependencies": {
|
"vue-template-compiler": "^2.6.11"
|
||||||
"@coreui/coreui": "^2.1.12",
|
},
|
||||||
"@coreui/icons": "^0.3.0",
|
"dependencies": {
|
||||||
"@ttskch/select2-bootstrap4-theme": "^1.2.3",
|
"@tailwindcss/ui": "^0.1.3",
|
||||||
"bootstrap": "^4.3.1",
|
"axios": "^0.19",
|
||||||
"bootstrap-sweetalert": "^1.0.1",
|
"cross-env": "^7.0",
|
||||||
"cross-env": "^5.2.0",
|
"jsignature": "^2.1.3",
|
||||||
"dropzone": "^5.5.1",
|
"laravel-mix": "^5.0.1",
|
||||||
"font-awesome": "^4.7.0",
|
"lodash": "^4.17.13",
|
||||||
"jquery": "^3.4.1",
|
"puppeteer": "^1.20.0",
|
||||||
"jsignature": "^2.1.3",
|
"resolve-url-loader": "^3.1.0",
|
||||||
"laravel-mix": "^4.1.2",
|
"sass": "^1.15.2",
|
||||||
"perfect-scrollbar": "^1.3.0",
|
"sass-loader": "^8.0.0",
|
||||||
"popper.js": "^1.14.3",
|
"tailwindcss": "^1.2.0"
|
||||||
"puppeteer": "^1.20.0",
|
}
|
||||||
"select2": "^4.0.8"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
6
public/css/app.css
vendored
6
public/css/app.css
vendored
File diff suppressed because one or more lines are too long
1
resources/js/app.js
vendored
Normal file
1
resources/js/app.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
// ..
|
@ -1,7 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
$LANG = array(
|
return [
|
||||||
|
'continue' => 'Continue',
|
||||||
|
'complete' => 'Complete',
|
||||||
|
'next' => 'Next',
|
||||||
|
'next_step' => 'Next step',
|
||||||
'organization' => 'Organization',
|
'organization' => 'Organization',
|
||||||
'name' => 'Name',
|
'name' => 'Name',
|
||||||
'website' => 'Website',
|
'website' => 'Website',
|
||||||
@ -263,6 +266,8 @@ $LANG = array(
|
|||||||
'notification_credit_viewed' => 'The following client :client viewed Credit :credit for :amount.',
|
'notification_credit_viewed' => 'The following client :client viewed Credit :credit for :amount.',
|
||||||
'notification_quote_viewed' => 'The following client :client viewed Quote :quote for :amount.',
|
'notification_quote_viewed' => 'The following client :client viewed Quote :quote for :amount.',
|
||||||
'reset_password' => 'You can reset your account password by clicking the following button:',
|
'reset_password' => 'You can reset your account password by clicking the following button:',
|
||||||
|
'reset_password_text' => 'Enter your email to reset your password.',
|
||||||
|
'password_reset' => 'Password reset',
|
||||||
'secure_payment' => 'Secure Payment',
|
'secure_payment' => 'Secure Payment',
|
||||||
'card_number' => 'Card Number',
|
'card_number' => 'Card Number',
|
||||||
'expiration_month' => 'Expiration Month',
|
'expiration_month' => 'Expiration Month',
|
||||||
@ -3135,8 +3140,4 @@ $LANG = array(
|
|||||||
'invoice_number_placeholder' => 'Invoice # :invoice',
|
'invoice_number_placeholder' => 'Invoice # :invoice',
|
||||||
'entity_number_placeholder' => ':entity # :entity_number',
|
'entity_number_placeholder' => ':entity # :entity_number',
|
||||||
'email_link_not_working' => 'If button above isn\'t working for you, please click on the link',
|
'email_link_not_working' => 'If button above isn\'t working for you, please click on the link',
|
||||||
);
|
];
|
||||||
|
|
||||||
return $LANG;
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
20
resources/sass/_variables.scss
vendored
20
resources/sass/_variables.scss
vendored
@ -1,20 +0,0 @@
|
|||||||
|
|
||||||
// Body
|
|
||||||
$body-bg: #f8fafc;
|
|
||||||
|
|
||||||
// Typography
|
|
||||||
$font-family-sans-serif: "Nunito", sans-serif;
|
|
||||||
$font-size-base: 0.9rem;
|
|
||||||
$line-height-base: 1.6;
|
|
||||||
|
|
||||||
// Colors
|
|
||||||
$blue: #3490dc;
|
|
||||||
$indigo: #6574cd;
|
|
||||||
$purple: #9561e2;
|
|
||||||
$pink: #f66D9b;
|
|
||||||
$red: #e3342f;
|
|
||||||
$orange: #f6993f;
|
|
||||||
$yellow: #ffed4a;
|
|
||||||
$green: #38c172;
|
|
||||||
$teal: #4dc0b5;
|
|
||||||
$cyan: #6cb2eb;
|
|
20
resources/sass/app.scss
vendored
20
resources/sass/app.scss
vendored
@ -1,14 +1,12 @@
|
|||||||
|
@tailwind base;
|
||||||
|
|
||||||
// Fonts
|
// ..
|
||||||
@import url('https://fonts.googleapis.com/css?family=Nunito');
|
@tailwind components;
|
||||||
|
|
||||||
// Variables
|
@import 'components/buttons';
|
||||||
@import 'variables';
|
@import 'components/validation';
|
||||||
|
@import 'components/inputs';
|
||||||
|
@import 'components/alerts';
|
||||||
|
|
||||||
// Bootstrap
|
// ..
|
||||||
@import '~bootstrap/scss/bootstrap';
|
@tailwind utilities;
|
||||||
|
|
||||||
.navbar-laravel {
|
|
||||||
background-color: #fff;
|
|
||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
|
|
||||||
}
|
|
||||||
|
11
resources/sass/components/alerts.scss
vendored
Normal file
11
resources/sass/components/alerts.scss
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
.alert {
|
||||||
|
@apply bg-gray-100 py-3 mt-4 px-4 text-sm border-l-2 mt-2 mb-1 bg-gray-100 border-gray-400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-success {
|
||||||
|
@apply border-green-500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-failure {
|
||||||
|
@apply border-red-500;
|
||||||
|
}
|
15
resources/sass/components/buttons.scss
vendored
Normal file
15
resources/sass/components/buttons.scss
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
.button {
|
||||||
|
@apply rounded py-3 px-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-primary {
|
||||||
|
@apply bg-blue-500 text-white;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
@apply bg-blue-600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-block {
|
||||||
|
@apply block w-full;
|
||||||
|
}
|
11
resources/sass/components/inputs.scss
vendored
Normal file
11
resources/sass/components/inputs.scss
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
.input {
|
||||||
|
@apply items-center border border-gray-300 rounded mt-2 w-full py-3 px-4;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
@apply outline-none border-blue-500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-label {
|
||||||
|
@apply text-sm text-gray-600;
|
||||||
|
}
|
11
resources/sass/components/validation.scss
vendored
Normal file
11
resources/sass/components/validation.scss
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
.validation {
|
||||||
|
@apply border-l-2 mt-2 mb-1 px-3 bg-gray-100 py-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.validation-fail {
|
||||||
|
@apply border-red-500 text-gray-700 text-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.validation-pass {
|
||||||
|
@apply border-green-500 text-gray-700 text-sm;
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
@extends('portal.ninja2020.layout.clean')
|
||||||
|
|
||||||
|
@section('body')
|
||||||
|
<div class="m-4">
|
||||||
|
<button class="button">Hello world</button>
|
||||||
|
</div>
|
||||||
|
@endsection
|
72
resources/views/portal/ninja2020/layout/clean.blade.php
Normal file
72
resources/views/portal/ninja2020/layout/clean.blade.php
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
|
||||||
|
<!-- Source: https://github.com/invoiceninja/invoiceninja -->
|
||||||
|
<!-- Error: {{ session('error') }} -->
|
||||||
|
|
||||||
|
@if (config('services.analytics.tracking_id'))
|
||||||
|
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-122229484-1"></script>
|
||||||
|
<script>
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
|
||||||
|
function gtag() {
|
||||||
|
dataLayer.push(arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
gtag('js', new Date());
|
||||||
|
gtag('config', '{{ config('services.analytics.tracking_id') }}', {'anonymize_ip': true});
|
||||||
|
|
||||||
|
function trackEvent(category, action) {
|
||||||
|
ga('send', 'event', category, action, this.src);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
Vue.config.devtools = true;
|
||||||
|
</script>
|
||||||
|
@else
|
||||||
|
<script>
|
||||||
|
function gtag() {
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<!-- Title -->
|
||||||
|
<title>@yield('meta_title', 'Invoice Ninja') | {{ config('app.name') }}</title>
|
||||||
|
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="description" content="@yield('meta_description')"/>
|
||||||
|
|
||||||
|
<!-- CSRF Token -->
|
||||||
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
|
|
||||||
|
<!-- Scripts -->
|
||||||
|
<script src="{{ mix('js/app.js') }}" defer></script>
|
||||||
|
|
||||||
|
<!-- Fonts -->
|
||||||
|
<link rel="dns-prefetch" href="https://fonts.gstatic.com">
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Open+Sans&display=swap" rel="stylesheet" type="text/css">
|
||||||
|
|
||||||
|
<!-- Styles -->
|
||||||
|
<link href="{{ mix('css/app.css') }}" rel="stylesheet">
|
||||||
|
{{-- <link href="{{ mix('favicon.png') }}" rel="shortcut icon" type="image/png"> --}}
|
||||||
|
|
||||||
|
<link rel="canonical" href="{{ config('ninja.site_url') }}/{{ request()->path() }}"/>
|
||||||
|
|
||||||
|
{{-- Feel free to push anything to header using @push('header') --}}
|
||||||
|
@stack('head')
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="antialiased">
|
||||||
|
@yield('body')
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
@yield('footer')
|
||||||
|
@stack('footer')
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</html>
|
@ -0,0 +1,37 @@
|
|||||||
|
@extends('portal.ninja2020.layout.clean')
|
||||||
|
@section('meta_title', ctrans('texts.password_recovery'))
|
||||||
|
|
||||||
|
@section('body')
|
||||||
|
<div class="flex h-screen">
|
||||||
|
<div class="m-auto md:w-1/3 lg:w-1/5">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<h1 class="text-center text-3xl">{{ ctrans('texts.password_recovery') }}</h1>
|
||||||
|
<p class="text-center opacity-75">{{ ctrans('texts.reset_password_text') }}</p>
|
||||||
|
@if(session('status'))
|
||||||
|
<div class="alert alert-success mt-4">
|
||||||
|
{{ session('status') }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
<form action="{{ route('password.email') }}" method="post" class="mt-6">
|
||||||
|
@csrf
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<label for="email" class="text-sm text-gray-600">{{ ctrans('texts.email_address') }}</label>
|
||||||
|
<input type="email" name="email" id="email"
|
||||||
|
class="input"
|
||||||
|
placeholder="user@example.com"
|
||||||
|
value="{{ old('email') }}"
|
||||||
|
autofocus>
|
||||||
|
@error('email')
|
||||||
|
<div class="validation validation-fail">
|
||||||
|
{{ $message }}
|
||||||
|
</div>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
<div class="mt-5">
|
||||||
|
<button class="button button-primary button-block">{{ ctrans('texts.next_step') }}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
@ -0,0 +1,58 @@
|
|||||||
|
@extends('portal.ninja2020.layout.clean')
|
||||||
|
@section('meta_title', ctrans('texts.password_reset'))
|
||||||
|
|
||||||
|
@section('body')
|
||||||
|
<div class="flex h-screen">
|
||||||
|
<div class="m-auto md:w-1/3 lg:w-1/5">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<h1 class="text-center text-3xl">{{ ctrans('texts.password_reset') }}</h1>
|
||||||
|
@if(session('status'))
|
||||||
|
<div class="alert alert-success mt-2">
|
||||||
|
{{ session('status') }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
<form action="{{ route('password.update') }}" method="post" class="mt-6">
|
||||||
|
@csrf
|
||||||
|
<input type="hidden" name="token" value="{{ $token }}">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<label for="email" class="input-label">{{ ctrans('texts.email_address') }}</label>
|
||||||
|
<input type="email" name="email" id="email"
|
||||||
|
class="input"
|
||||||
|
value="{{ $email ?? old('email') }}"
|
||||||
|
autofocus>
|
||||||
|
@error('email')
|
||||||
|
<div class="validation validation-fail">
|
||||||
|
{{ $message }}
|
||||||
|
</div>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col mt-4">
|
||||||
|
<label for="password" class="input-label">{{ ctrans('texts.password') }}</label>
|
||||||
|
<input type="password" name="password" id="password"
|
||||||
|
class="input"
|
||||||
|
autofocus>
|
||||||
|
@error('password')
|
||||||
|
<div class="validation validation-fail">
|
||||||
|
{{ $message }}
|
||||||
|
</div>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col mt-4">
|
||||||
|
<label for="password" class="input-label">{{ ctrans('texts.password') }}</label>
|
||||||
|
<input type="password" name="password_confirmation" id="password_confirmation"
|
||||||
|
class="input"
|
||||||
|
autofocus>
|
||||||
|
@error('password_confirmation')
|
||||||
|
<div class="validation validation-fail">
|
||||||
|
{{ $message }}
|
||||||
|
</div>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
<div class="mt-5">
|
||||||
|
<button class="button button-primary button-block">{{ ctrans('texts.complete') }}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
13
tailwind.config.js
vendored
Normal file
13
tailwind.config.js
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
const defaultTheme = require("tailwindcss/defaultTheme");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
fontFamily: {
|
||||||
|
sans: ["Open Sans", ...defaultTheme.fontFamily.sans]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
variants: {},
|
||||||
|
plugins: [require("@tailwindcss/ui")]
|
||||||
|
};
|
37
webpack.mix.js
vendored
37
webpack.mix.js
vendored
@ -1,4 +1,5 @@
|
|||||||
const mix = require('laravel-mix');
|
const mix = require("laravel-mix");
|
||||||
|
const tailwindcss = require("tailwindcss");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
@ -11,32 +12,12 @@ const mix = require('laravel-mix');
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
mix.js("resources/js/app.js", "public/js")
|
||||||
mix.copyDirectory('node_modules/@coreui/coreui/dist/css/coreui.min.css', 'public/vendors/css/coreui.min.css');
|
.sass("resources/sass/app.scss", "public/css")
|
||||||
mix.copyDirectory('node_modules/@coreui/icons/css/coreui-icons.min.css', 'public/vendors/css/coreui-icons.min.css');
|
.options({
|
||||||
mix.copyDirectory('node_modules/@coreui/coreui/dist/css/bootstrap.min.css', 'public/vendors/css/bootstrap.min.css');
|
processCssUrls: false,
|
||||||
mix.copyDirectory('node_modules/font-awesome/css/font-awesome.min.css', 'public/vendors/css/font-awesome.min.css');
|
postCss: [tailwindcss("./tailwind.config.js")]
|
||||||
mix.copyDirectory('node_modules/@coreui/coreui/dist/js/coreui.min.js', 'public/vendors/js/coreui.min.js');
|
});
|
||||||
mix.copyDirectory('node_modules/bootstrap/dist/js/bootstrap.bundle.min.js', 'public/vendors/js/bootstrap.bundle.min.js');
|
|
||||||
mix.copyDirectory('node_modules/jquery/dist/jquery.min.js', 'public/vendors/js/jquery.min.js');
|
|
||||||
mix.copyDirectory('node_modules/perfect-scrollbar/dist/perfect-scrollbar.min.js', 'public/vendors/js/perfect-scrollbar.min.js');
|
|
||||||
mix.copyDirectory('node_modules/jsignature/libs/jSignature.min.js', 'public/vendors/js/jSignature.min.js');
|
|
||||||
mix.copyDirectory('node_modules/jsignature/libs/flashcanvas.min.js', 'public/vendors/js/flashcanvas.min.js');
|
|
||||||
mix.copyDirectory('node_modules/jsignature/libs/flashcanvas.swf', 'public/vendors/js/flashcanvas.swf');
|
|
||||||
|
|
||||||
|
|
||||||
mix.copyDirectory('node_modules/select2/dist/css/select2.min.css', 'public/vendors/css/select2.min.css');
|
|
||||||
mix.copyDirectory('node_modules/select2/dist/js/select2.full.min.js', 'public/vendors/js/select2.min.js');
|
|
||||||
|
|
||||||
mix.copyDirectory('node_modules/@ttskch/select2-bootstrap4-theme/dist/select2-bootstrap4.min.css', 'public/vendors/css/select2-bootstrap4.css');
|
|
||||||
|
|
||||||
mix.copyDirectory('node_modules/dropzone/dist/min/dropzone.min.css', 'public/vendors/css/dropzone.min.css');
|
|
||||||
mix.copyDirectory('node_modules/dropzone/dist/min/basic.min.css', 'public/vendors/css/dropzone-basic.min.css');
|
|
||||||
mix.copyDirectory('node_modules/dropzone/dist/min/dropzone.min.js', 'public/vendors/js/dropzone.min.js');
|
|
||||||
|
|
||||||
mix.copyDirectory('node_modules/bootstrap-sweetalert/dist/sweetalert.css', 'public/vendors/css/sweetalert.css');
|
|
||||||
mix.copyDirectory('node_modules/bootstrap-sweetalert/dist/sweetalert.min.js', 'public/vendors/js/sweetalert.min.js');
|
|
||||||
|
|
||||||
mix.copyDirectory('node_modules/font-awesome/fonts', 'public/vendors/fonts');
|
|
||||||
|
|
||||||
mix.version();
|
mix.version();
|
||||||
|
mix.disableSuccessNotifications();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user