mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-24 02:14:21 -04:00
Client CRUD with VueJS (#2497)
* working on js localizations * remove dependencies * Pad Hashes to at least 10 characters in length * Inject JS translations into front end dynamically * Implement VueJS for Client Edit Page with reactivity * Conditionally hide rows if not enabled (custom_value) * Split client template into smaller components * implementing ui buttons * CRUD cycles of a client * Working on Client CRUD - Integrity constraint issues
This commit is contained in:
parent
7e57b0f2fd
commit
b989cf82b7
@ -3,6 +3,7 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\Client\EditClientRequest;
|
||||
use App\Http\Requests\Client\UpdateClientRequest;
|
||||
use App\Models\Client;
|
||||
use Illuminate\Http\Request;
|
||||
use Yajra\DataTables\Facades\DataTables;
|
||||
@ -10,7 +11,6 @@ use Yajra\DataTables\Html\Builder;
|
||||
|
||||
class ClientController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
@ -118,6 +118,7 @@ class ClientController extends Controller
|
||||
*/
|
||||
public function edit(EditClientRequest $request)
|
||||
{
|
||||
|
||||
$client = $request->entity(Client::class, request('client'));
|
||||
|
||||
$client->load('contacts', 'primary_billing_location', 'primary_shipping_location', 'locations', 'primary_contact');
|
||||
@ -138,9 +139,21 @@ class ClientController extends Controller
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
public function update(UpdateClientRequest $request, $id)
|
||||
{
|
||||
//
|
||||
\Illuminate\Support\Facades\Log::error(print_r($request->input('contacts'),1));
|
||||
|
||||
$client = $request->entity(Client::class, request('client'));
|
||||
|
||||
$client->fill($request->all())->save();
|
||||
|
||||
$client->contacts()->delete();
|
||||
$client->contacts()->create($request->input('contacts'));
|
||||
|
||||
$client->load('contacts', 'primary_billing_location', 'primary_shipping_location', 'locations', 'primary_contact');
|
||||
|
||||
return response()->json($client, 200);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
101
app/Http/Controllers/TranslationController.php
Normal file
101
app/Http/Controllers/TranslationController.php
Normal file
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class TranslationController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$strings = Cache::rememberForever('lang.js', function () {
|
||||
$lang = config('app.locale');
|
||||
|
||||
$files = glob(resource_path('lang/' . $lang . '/*.php'));
|
||||
$strings = [];
|
||||
|
||||
foreach ($files as $file) {
|
||||
$name = basename($file, '.php');
|
||||
$strings[$name] = require $file;
|
||||
}
|
||||
|
||||
return $strings;
|
||||
});
|
||||
|
||||
header('Content-Type: text/javascript');
|
||||
echo('window.i18n = ' . json_encode($strings) . ';');
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
@ -18,5 +18,15 @@ class EditClientRequest extends Request
|
||||
// return ! auth()->user(); //todo permissions
|
||||
}
|
||||
|
||||
public function sanitize()
|
||||
{
|
||||
$input = $this->all();
|
||||
|
||||
//$input['id'] = $this->encodePrimaryKey($input['id']);
|
||||
|
||||
//$this->replace($input);
|
||||
|
||||
return $this->all();
|
||||
}
|
||||
|
||||
}
|
30
app/Http/Requests/Client/UpdateClientRequest.php
Normal file
30
app/Http/Requests/Client/UpdateClientRequest.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Client;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
|
||||
class UpdateClientRequest extends Request
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
// return ! auth()->user(); //todo permissions
|
||||
}
|
||||
|
||||
public function rules()
|
||||
|
||||
{
|
||||
return [
|
||||
'name' => 'required',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -3,13 +3,44 @@
|
||||
namespace App\Models;
|
||||
|
||||
use Laracasts\Presenter\PresentableTrait;
|
||||
use Hashids\Hashids;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
|
||||
class Client extends BaseModel
|
||||
{
|
||||
use PresentableTrait;
|
||||
use MakesHash;
|
||||
|
||||
protected $presenter = 'App\Models\Presenters\ClientPresenter';
|
||||
|
||||
protected $appends = ['hash_id'];
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'id_number',
|
||||
'vat_number',
|
||||
'work_phone',
|
||||
'custom_value1',
|
||||
'custom_value2',
|
||||
'address1',
|
||||
'address2',
|
||||
'city',
|
||||
'state',
|
||||
'postal_code',
|
||||
'country_id',
|
||||
'private_notes',
|
||||
'size_id',
|
||||
'industry_id',
|
||||
'currency_id',
|
||||
'language_id',
|
||||
'payment_terms',
|
||||
'website',
|
||||
];
|
||||
|
||||
public function getHashIdAttribute()
|
||||
{
|
||||
return $this->encodePrimaryKey($this->id);
|
||||
}
|
||||
|
||||
public function contacts()
|
||||
{
|
||||
|
@ -20,9 +20,15 @@ class ClientContact extends Authenticatable
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'first_name', 'last_name', 'email', 'password',
|
||||
'first_name',
|
||||
'last_name',
|
||||
'email',
|
||||
'password',
|
||||
'phone',
|
||||
'custom_value1',
|
||||
'custom_value2',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* The attributes that should be hidden for arrays.
|
||||
*
|
||||
|
@ -36,21 +36,21 @@ trait MakesHash
|
||||
*/
|
||||
public function getDbCode($db) : string
|
||||
{
|
||||
$hashids = new Hashids();
|
||||
$hashids = new Hashids('', 10);
|
||||
|
||||
return $hashids->encode( str_replace( MultiDB::DB_PREFIX, "", $db ) );
|
||||
}
|
||||
|
||||
public function encodePrimaryKey($value)
|
||||
{
|
||||
$hashids = new Hashids();
|
||||
$hashids = new Hashids('', 10);
|
||||
|
||||
return $hashids->encode($value);
|
||||
}
|
||||
|
||||
public function decodePrimaryKey($value)
|
||||
{
|
||||
$hashids = new Hashids();
|
||||
$hashids = new Hashids('', 10);
|
||||
|
||||
$decoded_array = $hashids->decode($value);
|
||||
|
||||
|
@ -27,7 +27,6 @@
|
||||
"laravel/framework": "5.7.*",
|
||||
"laravel/socialite": "^3.1",
|
||||
"laravel/tinker": "^1.0",
|
||||
"mariuzzo/laravel-js-localization": "^1.4",
|
||||
"nwidart/laravel-modules": "^4.0",
|
||||
"predis/predis": "^1.1",
|
||||
"spatie/laravel-html": "^2.19",
|
||||
|
131
composer.lock
generated
131
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "b872ce32e507245bb3568a6a1bd18c51",
|
||||
"content-hash": "753b0ff8fa34e1e5a54d950d3d780d30",
|
||||
"packages": [
|
||||
{
|
||||
"name": "asgrim/ofxparser",
|
||||
@ -1473,89 +1473,6 @@
|
||||
],
|
||||
"time": "2018-11-01T10:33:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mariuzzo/laravel-js-localization",
|
||||
"version": "v1.4.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/rmariuzzo/Laravel-JS-Localization.git",
|
||||
"reference": "e36ea8dadfa680d862262af2ea4abbe5697bc03e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/rmariuzzo/Laravel-JS-Localization/zipball/e36ea8dadfa680d862262af2ea4abbe5697bc03e",
|
||||
"reference": "e36ea8dadfa680d862262af2ea4abbe5697bc03e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/config": ">=4.2",
|
||||
"illuminate/console": ">=4.2",
|
||||
"illuminate/filesystem": ">=4.2",
|
||||
"php": ">=5.4.0",
|
||||
"tedivm/jshrink": "1.0.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "4.8.*"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Mariuzzo\\LaravelJsLocalization\\LaravelJsLocalizationServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Mariuzzo\\LaravelJsLocalization\\": "src/Mariuzzo/LaravelJsLocalization/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Rubens Mariuzzo",
|
||||
"email": "rubens@mariuzzo.com",
|
||||
"homepage": "https://github.com/rmariuzzo",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "German Popoter",
|
||||
"email": "me@gpopoteur.com",
|
||||
"homepage": "https://github.com/gpopoteur",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Galievskiy Dmitriy",
|
||||
"homepage": "https://github.com/xAockd",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Ramon Ackermann",
|
||||
"homepage": "https://github.com/sboo",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Pe Ell",
|
||||
"homepage": "https://github.com/a-komarev",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Laravel Localization in JavaScript",
|
||||
"homepage": "https://github.com/rmariuzzo/laravel-js-localization",
|
||||
"keywords": [
|
||||
"JS",
|
||||
"i18n",
|
||||
"javascript",
|
||||
"lang",
|
||||
"laravel",
|
||||
"laravel 5",
|
||||
"localization"
|
||||
],
|
||||
"time": "2017-11-23T04:07:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "markbaker/complex",
|
||||
"version": "1.4.7",
|
||||
@ -3497,52 +3414,6 @@
|
||||
],
|
||||
"time": "2018-10-02T16:36:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "tedivm/jshrink",
|
||||
"version": "v1.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/tedious/JShrink.git",
|
||||
"reference": "7575d9d96f113bc7c1c28ec8231ee086751a9078"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/tedious/JShrink/zipball/7575d9d96f113bc7c1c28ec8231ee086751a9078",
|
||||
"reference": "7575d9d96f113bc7c1c28ec8231ee086751a9078",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"fabpot/php-cs-fixer": "0.4.0",
|
||||
"phpunit/phpunit": "4.0.*",
|
||||
"satooshi/php-coveralls": "dev-master"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"JShrink": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Robert Hafner",
|
||||
"email": "tedivm@tedivm.com"
|
||||
}
|
||||
],
|
||||
"description": "Javascript Minifier built in PHP",
|
||||
"homepage": "http://github.com/tedious/JShrink",
|
||||
"keywords": [
|
||||
"javascript",
|
||||
"minifier"
|
||||
],
|
||||
"time": "2014-11-11T03:54:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "tijsverkoyen/css-to-inline-styles",
|
||||
"version": "2.2.1",
|
||||
|
@ -29,8 +29,10 @@
|
||||
"vue": "^2.5.17"
|
||||
},
|
||||
"dependencies": {
|
||||
"hashids": "^1.2.2",
|
||||
"laravel-echo": "^1.4.0",
|
||||
"quill": "^1.3.6",
|
||||
"socket.io-client": "^2.1.1"
|
||||
"socket.io-client": "^2.1.1",
|
||||
"vue-i18n": "^8.3.0"
|
||||
}
|
||||
}
|
||||
|
16890
public/css/ninja.css
vendored
16890
public/css/ninja.css
vendored
File diff suppressed because one or more lines are too long
16890
public/css/ninja.min.css
vendored
16890
public/css/ninja.min.css
vendored
File diff suppressed because one or more lines are too long
32566
public/js/ninja.js
vendored
32566
public/js/ninja.js
vendored
File diff suppressed because one or more lines are too long
32566
public/js/ninja.min.js
vendored
32566
public/js/ninja.min.js
vendored
File diff suppressed because one or more lines are too long
106
resources/assets/js/vendor/I18n.js
vendored
Normal file
106
resources/assets/js/vendor/I18n.js
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
export default class I18n
|
||||
{
|
||||
/**
|
||||
* Initialize a new translation instance.
|
||||
*
|
||||
* @param {string} key
|
||||
* @return {void}
|
||||
*/
|
||||
constructor(key = 'translations')
|
||||
{
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get and replace the string of the given key.
|
||||
*
|
||||
* @param {string} key
|
||||
* @param {object} replace
|
||||
* @return {string}
|
||||
*/
|
||||
trans(key, replace = {})
|
||||
{
|
||||
return this._replace(this._extract(key), replace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get and pluralize the strings of the given key.
|
||||
*
|
||||
* @param {string} key
|
||||
* @param {number} count
|
||||
* @param {object} replace
|
||||
* @return {string}
|
||||
*/
|
||||
trans_choice(key, count = 1, replace = {})
|
||||
{
|
||||
let translations = this._extract(key, '|').split('|'), translation;
|
||||
|
||||
translations.some(t => translation = this._match(t, count));
|
||||
|
||||
translation = translation || (count > 1 ? translations[1] : translations[0]);
|
||||
|
||||
return this._replace(translation, replace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Match the translation limit with the count.
|
||||
*
|
||||
* @param {string} translation
|
||||
* @param {number} count
|
||||
* @return {string|null}
|
||||
*/
|
||||
_match(translation, count)
|
||||
{
|
||||
let match = translation.match(/^[\{\[]([^\[\]\{\}]*)[\}\]](.*)/);
|
||||
|
||||
if (! match) return;
|
||||
|
||||
if (match[1].includes(',')) {
|
||||
let [from, to] = match[1].split(',');
|
||||
|
||||
if (to === '*' && count >= from) {
|
||||
return match[2];
|
||||
} else if (from === '*' && count <= to) {
|
||||
return match[2];
|
||||
} else if (count >= from && count <= to) {
|
||||
return match[2];
|
||||
}
|
||||
}
|
||||
|
||||
return match[1] == count ? match[2] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the placeholders.
|
||||
*
|
||||
* @param {string} translation
|
||||
* @param {object} replace
|
||||
* @return {string}
|
||||
*/
|
||||
_replace(translation, replace)
|
||||
{
|
||||
for (let placeholder in replace) {
|
||||
translation = translation
|
||||
.replace(`:${placeholder}`, replace[placeholder])
|
||||
.replace(`:${placeholder.toUpperCase()}`, replace[placeholder].toUpperCase())
|
||||
.replace(
|
||||
`:${placeholder.charAt(0).toUpperCase()}${placeholder.slice(1)}`,
|
||||
replace[placeholder].charAt(0).toUpperCase()+replace[placeholder].slice(1)
|
||||
);
|
||||
}
|
||||
|
||||
return translation.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* The extract helper.
|
||||
*
|
||||
* @param {string} key
|
||||
* @param {mixed} value
|
||||
* @return {mixed}
|
||||
*/
|
||||
_extract(key, value = null)
|
||||
{
|
||||
return key.toString().split('.').reduce((t, i) => t[i] || (value || key), window[this.key]);
|
||||
}
|
||||
}
|
81762
resources/assets/js/vue-i18n-locales.generated.js
vendored
Normal file
81762
resources/assets/js/vue-i18n-locales.generated.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
16
resources/js/app.js
vendored
16
resources/js/app.js
vendored
@ -6,11 +6,20 @@
|
||||
*/
|
||||
|
||||
require('./bootstrap');
|
||||
|
||||
window.Vue = require('vue');
|
||||
|
||||
/* Development only*/
|
||||
Vue.config.devtools = true;
|
||||
|
||||
window.axios = require('axios');
|
||||
window.axios.defaults.headers.common = {
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
'X-CSRF-TOKEN' : document.querySelector('meta[name="csrf-token"]').getAttribute('content')
|
||||
};
|
||||
|
||||
/* Allows us to use our native translation easily using {{ trans() }} syntax */
|
||||
const _ = require('lodash');
|
||||
Vue.prototype.trans = string => _.get(window.i18n, string);
|
||||
|
||||
/**
|
||||
* Next, we will create a fresh Vue application instance and attach it to
|
||||
* the page. Then, you may begin adding components to this application
|
||||
@ -18,6 +27,9 @@ Vue.config.devtools = true;
|
||||
*/
|
||||
|
||||
Vue.component('example-component', require('./components/ExampleComponent.vue'));
|
||||
Vue.component('client-edit', require('./components/client/ClientEdit.vue'));
|
||||
Vue.component('client-edit-form', require('./components/client/ClientEditForm.vue'));
|
||||
Vue.component('contact-edit', require('./components/client/ClientContactEdit.vue'));
|
||||
|
||||
window.onload = function () {
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
<div class="card-body">
|
||||
I'm an example component.
|
||||
{{ trans('texts.clients')}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
55
resources/js/components/client/ClientContactEdit.vue
Normal file
55
resources/js/components/client/ClientContactEdit.vue
Normal file
@ -0,0 +1,55 @@
|
||||
<template>
|
||||
<div class="card-body">
|
||||
<div class="form-group row">
|
||||
<label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.first_name') }}</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" name="first_name" :placeholder="trans('texts.first_name')" v-model="contact.first_name" class="form-control" id="first_name">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.last_name') }}</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" name="last_name" :placeholder="trans('texts.last_name')" v-model="contact.last_name" class="form-control" id="last_name">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.email') }}</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="email" name="email" :placeholder="trans('texts.email')" v-model="contact.email" class="form-control" id="email">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.phone') }}</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" name="phone" :placeholder="trans('texts.phone')" v-model="contact.phone" class="form-control" id="phone">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row" v-if="contact.custom_value1">
|
||||
<label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.custom_value1') }}</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" name="custom_value1" :placeholder="trans('texts.custom_value1')" v-model="contact.custom_value1" class="form-control" id="custom_value1">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row" v-if="contact.custom_value1">
|
||||
<label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.custom_value2') }}</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" name="custom_value2" :placeholder="trans('texts.custom_value2')" v-model="contact.custom_value2" class="form-control" id="custom_value2">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="float-right">
|
||||
<button type="button" class="btn btn-danger" v-on:click="$emit('remove',contact.id)"> {{ trans('texts.remove_contact') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['contact']
|
||||
}
|
||||
</script>
|
51
resources/js/components/client/ClientEdit.vue
Normal file
51
resources/js/components/client/ClientEdit.vue
Normal file
@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<div class="card-body">
|
||||
<div class="form-group row">
|
||||
<label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.client_name') }}</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" name="name" :placeholder="trans('texts.client_name')" v-model="client.name" class="form-control" id="name">
|
||||
</div>
|
||||
<div v-if="errors && errors.name" class="text-danger">{{ errors.name[0] }}</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.id_number') }}</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" name="id_number" :placeholder="trans('texts.id_number')" v-model="client.id_number" class="form-control" id="id_number">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.vat_number') }}</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" name="vat_number" :placeholder="trans('texts.vat_number')" v-model="client.vat_number" class="form-control" id="vat_number">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.website') }}</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" name="website" :placeholder="trans('texts.website')" v-model="client.website" class="form-control" id="websites">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row" v-if="client.custom_value1">
|
||||
<label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.custom_value1') }}</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" name="custom_value1" :placeholder="trans('texts.custom_value1')" v-model="client.custom_value1" class="form-control" id="custom_value1">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.custom_value2') }}</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" name="custom_value2" :placeholder="trans('texts.custom_value2')" v-model="client.custom_value2" class="form-control" id="custom_value2">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: ['client','errors']
|
||||
}
|
||||
</script>
|
104
resources/js/components/client/ClientEditForm.vue
Normal file
104
resources/js/components/client/ClientEditForm.vue
Normal file
@ -0,0 +1,104 @@
|
||||
<template>
|
||||
<form @submit.prevent="submit">
|
||||
<div class="container-fluid">
|
||||
<div class="row form-group">
|
||||
<div class="col-md-12">
|
||||
<span class="float-right">
|
||||
<div class="btn-group ml-2">
|
||||
<button class="btn btn-lg btn-success" type="button" @click="submit"><i class="fa fa-save"></i> {{ trans('texts.save') }}</button>
|
||||
<button class="btn btn-lg btn-success dropdown-toggle dropdown-toggle-split" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="sr-only">Toggle Dropdown</span>
|
||||
</button>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item" href="#"><i class="fa fa-plus-circle"></i> {{ trans('texts.add_contact') }}</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="#">{{ trans('texts.archive_client') }}</a>
|
||||
<a class="dropdown-item" href="#">{{ trans('texts.delete_client') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header bg-primary2">{{ trans('texts.edit_client') }}</div>
|
||||
|
||||
<client-edit :client="client" :errors="errors"></client-edit>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header bg-primary2">{{ trans('texts.contact_information') }}
|
||||
<span class="float-right">
|
||||
<button type="button" class="btn btn-primary btn-sm"><i class="fa fa-plus-circle"></i> {{ trans('texts.add_contact') }}</button>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<contact-edit v-for="(contact, index) in client.contacts"
|
||||
v-bind:contact="contact"
|
||||
v-bind:index="index"
|
||||
:key="contact.id"
|
||||
@remove="remove"></contact-edit>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: function () {
|
||||
return {
|
||||
'client': [],
|
||||
'errors': [],
|
||||
}
|
||||
},
|
||||
props: {
|
||||
clientdata: {
|
||||
type: [Object,Array],
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
beforeMount: function () {
|
||||
this.client = this.clientdata;
|
||||
},
|
||||
methods: {
|
||||
remove (itemId) {
|
||||
this.client.contacts = this.client.contacts.filter(function (item) {
|
||||
return itemId != item.id;
|
||||
});
|
||||
},
|
||||
submit() {
|
||||
this.errors = {};
|
||||
|
||||
|
||||
axios.put('/clients/' + this.client.hash_id, this.client).then(response => {
|
||||
this.client = response.data;
|
||||
console.dir(response);
|
||||
}).catch(error => {
|
||||
if (error.response.status === 422) {
|
||||
this.errors = error.response.data.errors || {};
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
},
|
||||
created:function() {
|
||||
//console.dir('created');
|
||||
|
||||
},
|
||||
updated:function() {
|
||||
//console.dir('updated');
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
@ -1,43 +1,12 @@
|
||||
@extends('layouts.master', ['header' => $header])
|
||||
|
||||
@section('head')
|
||||
@parent
|
||||
<link rel="stylesheet" href="//cdn.datatables.net/1.10.18/css/dataTables.bootstrap4.min.css">
|
||||
<script src="//cdn.datatables.net/1.10.18/js/jquery.dataTables.min.js"></script>
|
||||
<script src="//cdn.datatables.net/1.10.18/js/dataTables.bootstrap4.min.js"></script>
|
||||
@endsection
|
||||
|
||||
@section('body')
|
||||
|
||||
<main class="main">
|
||||
<main class="main" id="app">
|
||||
<!-- Breadcrumb-->
|
||||
{{ Breadcrumbs::render('clients.edit', $client) }}
|
||||
|
||||
<div class="container-fluid" >
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
|
||||
{{ html()->form('PUT', route('signup.submit'))->open() }}
|
||||
|
||||
<example-component></example-component>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{{ html()->form()->close() }}
|
||||
</div>
|
||||
<client-edit-form v-bind:clientdata="{{ $client }}"></client-edit-form>
|
||||
|
||||
</main>
|
||||
|
||||
@endsection
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@endsection
|
@ -7,7 +7,6 @@
|
||||
<script src="//cdn.datatables.net/1.10.18/js/dataTables.bootstrap4.min.js"></script>
|
||||
@endsection
|
||||
|
||||
|
||||
@section('body')
|
||||
@parent
|
||||
<main class="main" >
|
||||
@ -26,15 +25,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@endsection
|
||||
|
||||
@section('footer')
|
||||
@parent
|
||||
{!! $html->scripts() !!}
|
||||
|
||||
@endsection
|
||||
|
||||
|
||||
|
||||
|
||||
@endsection
|
@ -3,11 +3,17 @@
|
||||
@section('body')
|
||||
<main class="main">
|
||||
<!-- Breadcrumb-->
|
||||
{{ Breadcrumbs::render('dashboard') }}
|
||||
{{ Breadcrumbs::render('dashboard') }}
|
||||
<div class="container-fluid">
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-lg-12">
|
||||
<div class="col-lg-6">test</div>
|
||||
<div class="col-lg-6">test2</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@endsection
|
||||
|
@ -9,6 +9,4 @@
|
||||
</body>
|
||||
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
|
@ -63,28 +63,34 @@
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
|
||||
<script src=" {{ mix('/js/ninja.min.js') }}"></script>
|
||||
<script src="/js/lang.js"></script>
|
||||
<style type="text/css">
|
||||
.bg-primary2 {
|
||||
background-color: #167090 !important;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
a.bg-primary2:hover, a.bg-primary:focus,
|
||||
button.bg-primary:hover,
|
||||
button.bg-primary:focus {
|
||||
background-color: #56b3d4 !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
@yield('head')
|
||||
|
||||
</head>
|
||||
|
||||
|
||||
@include('header', $header)
|
||||
@yield('header')
|
||||
|
||||
|
||||
@include('sidebar')
|
||||
@yield('sidebar')
|
||||
|
||||
|
||||
@section('body')
|
||||
@yield('body')
|
||||
|
||||
@include('dashboard.aside')
|
||||
|
||||
|
||||
@include('footer')
|
||||
@yield('footer')
|
||||
|
||||
|
||||
</html>
|
@ -1,5 +1,4 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Authentication Routes Laravel Defaults... replaces //Auth::routes();
|
||||
*/
|
||||
@ -71,6 +70,12 @@ Route::group(['prefix' => 'contact', 'middleware' => 'auth:contact'], function
|
||||
|
||||
});
|
||||
|
||||
/*
|
||||
* Injects users translation strings in json format for frontend consumption.
|
||||
*/
|
||||
Route::get('js/lang.js', 'TranslationController@index')->name('assets.lang');
|
||||
|
||||
|
||||
|
||||
/* Dev Playground
|
||||
Route::get('/mailable', function () {
|
||||
|
2
webpack.mix.js
vendored
2
webpack.mix.js
vendored
@ -15,8 +15,6 @@ mix.js('resources/js/app.js', 'public/js/vendor');
|
||||
|
||||
mix.scripts([
|
||||
'node_modules/@coreui/coreui/dist/js/coreui.js',
|
||||
//'node_modules/vue/dist/vue.min.js',
|
||||
//'node_modules/vue/dist/vue.js',
|
||||
'public/js/vendor/app.js'
|
||||
], 'public/js/ninja.js');
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user