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);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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,7 +20,13 @@ 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',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,14 @@
|
|||
{{ 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 () {
|
||||
|
|
|
|||
|
|
@ -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…
Reference in New Issue