Implement Typescript (#2514)

* Add contact

* Saving client and contacts

* working on ts implementation

* Need to pass  into TS

* client_edit.ts

* Need to pass  into TS

* declare variables
This commit is contained in:
David Bomba 2018-11-22 22:12:41 +11:00 committed by GitHub
parent 0f66625cdf
commit fa83ce10a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 261 additions and 94 deletions

View File

@ -5,12 +5,21 @@ namespace App\Http\Controllers;
use App\Http\Requests\Client\EditClientRequest;
use App\Http\Requests\Client\UpdateClientRequest;
use App\Models\Client;
use App\Repositories\ClientRepository;
use Illuminate\Http\Request;
use Yajra\DataTables\Facades\DataTables;
use Yajra\DataTables\Html\Builder;
class ClientController extends Controller
{
protected $clientRepo;
public function __construct(ClientRepository $clientRepo)
{
$this->clientRepo = $clientRepo;
}
/**
* Display a listing of the resource.
*
@ -122,14 +131,11 @@ class ClientController extends Controller
public function edit(EditClientRequest $request, Client $client)
{
$client->load('contacts', 'primary_contact');
$data = [
'header' => $this->headerData(),
'client' => $client,
];
return view('client.edit', $data);
}
@ -140,16 +146,10 @@ class ClientController extends Controller
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(UpdateClientRequest $request, $id)
public function update(UpdateClientRequest $request, Client $client)
{
$client = $request->entity(Client::class, request('client'));
$client->fill($request->all())->save();
$client->contacts()->delete();
$client->contacts()->create($request->input('contacts'));
$client = $this->clientRepo->save($request, $client);
$client->load('contacts', 'primary_contact');
return response()->json($client, 200);

View File

@ -27,7 +27,6 @@ class ClientContact extends Authenticatable
];
protected $hidden = [
'id',
'password',
'remember_token',
];

View File

@ -0,0 +1,8 @@
<?php
namespace App\Models\Presenters;
class ClientContactPresenter extends EntityPresenter
{
}

View File

@ -29,7 +29,11 @@ class RouteServiceProvider extends ServiceProvider
parent::boot();
Route::bind('client', function ($value) {
return \App\Models\Client::where('id', $this->decodePrimaryKey($value))->first() ?? abort(404);
$client = \App\Models\Client::where('id', $this->decodePrimaryKey($value))->first() ?? abort(404);
$client->load('contacts', 'primary_contact');
return $client;
});
Route::bind('invoice', function ($value) {

View File

@ -0,0 +1,12 @@
<?php
namespace App\Repositories;
/**
*
*/
class BaseRepository
{
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\Repositories;
/**
*
*/
class ClientContactRepository extends BaseRepository
{
public function save($data)
{
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace App\Repositories;
use App\Repositories\ClientContactRepository;
/**
*
*/
class ClientRepository extends BaseRepository
{
protected $clientContactRepository;
public function __construct(ClientContactRepository $clientContactRepository)
{
$this->clientContactRepository = $clientContactRepository;
}
public function save($data)
{
$client->fill($request->all())->save();
}
}

View File

@ -33,6 +33,8 @@
"laravel-echo": "^1.4.0",
"quill": "^1.3.6",
"socket.io-client": "^2.1.1",
"ts-loader": "3.5.0",
"typescript": "^3.1.6",
"vue-i18n": "^8.3.0"
}
}

1
public/js/client_edit.js vendored Normal file

File diff suppressed because one or more lines are too long

5
public/js/ninja.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

5
resources/js/app.js vendored
View File

@ -6,7 +6,7 @@
*/
require('./bootstrap');
window.Vue = require('vue');
//window.Vue = require('vue');
/* Development only*/
Vue.config.devtools = true;
@ -31,7 +31,7 @@ Vue.component('client-primary-address', require('./components/client/ClientPrima
Vue.component('generic-address', require('./components/generic/Address.vue'));
Vue.component('client-edit-form', require('./components/client/ClientEditForm.vue'));
Vue.component('contact-edit', require('./components/client/ClientContactEdit.vue'));
*/
window.onload = function () {
const app = new Vue({
@ -39,3 +39,4 @@ window.onload = function () {
});
}
*/

View File

@ -89,7 +89,6 @@ export default {
submit() {
this.errors = {};
axios.put('/clients/' + this.client.hash_id, this.client).then(response => {
this.client = response.data;
console.dir(response);

View File

@ -0,0 +1,79 @@
//import * as Vue from 'vue';
import Vue from 'vue';
import axios, { AxiosRequestConfig, AxiosPromise } from 'axios';
var VueApp: any = Vue;
declare var clientObject: any;
var App = new VueApp({
el : '#client_edit',
data: function () {
return {
'client': [],
'errors': [],
}
},
mounted(this: any) {
//this.client = {!! $client !!};
this.client = clientObject;
console.dir(this.client);
},
beforeMount: function () {
console.log('before mount')
},
created:function() {
console.dir('created')
},
updated:function() {
console.dir('updated')
},
methods:{
remove(this: any, contact:any){
let index = this.client.contacts.indexOf(contact);
this.client.contacts.splice(index, 1);
},
add(this: any){
console.dir('i will add a contact here')
this.client.contacts.push({first_name: '', last_name: '', email: '', phone: ''});
window.scrollTo(0, document.body.scrollHeight || document.documentElement.scrollHeight);
this.$nextTick(() => {
let index = this.client.contacts.length - 1;
let input = this.$refs.first_name[index];
input.focus();
});
},
submit(this: any) {
this.errors = {};
axios.put('/clients/', this.client).then(response => {
// axios.put('/clients/' + {{ $client->present()->id }}, this.client).then(response => {
this.client = response.data;
}).catch(error => {
if (error.response.status === 422) {
this.errors = error.response.data.errors || {};
}
else if(error.response.status === 419) {
//csrf token has expired, we'll need to force a page reload
}
});
},
copy(type: any) {
if(type.includes('copy_billing')){
this.client.shipping_address1 = this.client.address1;
this.client.shipping_address2 = this.client.address2;
this.client.shipping_city = this.client.city;
this.client.shipping_state = this.client.state;
this.client.shipping_postal_code = this.client.postal_code;
this.client.shipping_country_id = this.client.country_id;
}else {
this.client.address1 = this.client.shipping_address1;
this.client.address2 = this.client.shipping_address2;
this.client.city = this.client.shipping_city;
this.client.state = this.client.shipping_state;
this.client.postal_code = this.client.shipping_postal_code;
this.client.country_id = this.client.shipping_country_id;
}
}
}
});

View File

@ -2,29 +2,12 @@
@section('body')
<main class="main" id="client_edit">
<!-- Breadcrumb-->
{{ Breadcrumbs::render('clients.edit', $client) }}
<form>
<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"><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">
<!-- Client Details and Address Column -->
@ -42,7 +25,7 @@
<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>
<button type="button" class="btn btn-primary btn-sm" @click="add()"><i class="fa fa-plus-circle"></i> {{ trans('texts.add_contact') }}</button>
</span>
</div>
@ -54,55 +37,21 @@
</div>
<!-- End Contact Details Column -->
</div>
<div class="row">
<div class="col-md-12 text-center">
<button class="btn btn-lg btn-success" type="button" @click="submit"><i class="fa fa-save"></i> {{ trans('texts.save') }}</button>
</div>
</div>
</div>
</form>
<script>
new Vue({
el : '#client_edit',
data: function () {
return {
'client': [],
'errors': [],
}
},
mounted() {
console.log('Component mounted.')
//this.getItinerary()
this.client = {!! $client !!}
},
beforeMount: function () {
console.log('before mount')
},
created:function() {
console.dir('created')
},
updated:function() {
console.dir('updated');
},
methods:{
copy(type) {
console.dir('inside ');
if(type.includes('copy_billing')){
this.client.shipping_address1 = this.client.address1;
this.client.shipping_address2 = this.client.address2;
this.client.shipping_city = this.client.city;
this.client.shipping_state = this.client.state;
this.client.shipping_postal_code = this.client.postal_code;
this.client.shipping_country_id = this.client.country_id;
}else {
this.client.address1 = this.client.shipping_address1;
this.client.address2 = this.client.shipping_address2;
this.client.city = this.client.shipping_city;
this.client.state = this.client.shipping_state;
this.client.postal_code = this.client.shipping_postal_code;
this.client.country_id = this.client.shipping_country_id;
}
}
}
});
var clientObject = {!! $client !!};
</script>
<script src=" {{ mix('/js/client_edit.js') }}"></script>
</main>
@endsection

View File

@ -4,7 +4,8 @@
<div class="form-group row">
<label for="name" class="col-sm-3 col-form-label text-right">@lang('texts.client_name')</label>
<div class="col-sm-9">
<input name="name" placeholder="@lang('texts.name')" class="form-control" v-model="client.name" value="{{ $client->present()->name }}" id="name">
<input name="name" placeholder="@lang('texts.name')" class="form-control" v-model="client.name" value="{{ $client->present()->name }}">
<div v-if="errors && errors.name" class="text-danger">@{{ errors.name[0] }}</div>
</div>
</div>

View File

@ -3,7 +3,7 @@
<label for="name" class="col-sm-3 col-form-label text-right">@lang('texts.first_name')</label>
<div class="col-sm-9">
<input name="id" type="hidden" v-model="contact.id" value="{{ $client->present()->id }}">
<input name="first_name" placeholder="@lang('texts.first_name')" class="form-control" v-model="contact.first_name">
<input ref="first_name" name="first_name" placeholder="@lang('texts.first_name')" class="form-control" v-model="contact.first_name">
</div>
</div>
@ -42,7 +42,7 @@
</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>
<button type="button" class="btn btn-danger" v-on:click="remove(contact)"> {{ trans('texts.remove_contact') }}</button>
</div>
</div>

62
tsconfig.json Normal file
View File

@ -0,0 +1,62 @@
{
"compilerOptions": {
/* Basic Options */
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', -> 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
// "lib": [], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
"sourceMap": false, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
// "outDir": "./", /* Redirect output structure to the directory. */
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": false, /* Enable all strict type-checking options. */
"noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
},
"include": [
"resources/js/ts/**/*"
]
}

19
webpack.mix.js vendored
View File

@ -11,11 +11,27 @@ const mix = require('laravel-mix');
|
*/
mix.webpackConfig({
resolve: {
extensions: ['.ts']
},
module: {
rules: [
{
test: /\.ts$/,
loader: 'ts-loader'
}
]
}
});
mix.js('resources/js/ts/client/client_edit.ts', 'public/js');
mix.js('resources/js/app.js', 'public/js/vendor');
mix.scripts([
'node_modules/@coreui/coreui/dist/js/coreui.js',
'public/js/vendor/app.js'
//'public/js/vendor/app.js'
], 'public/js/ninja.js');
mix.minify('public/js/ninja.js');
@ -31,5 +47,4 @@ mix.minify('public/css/ninja.css');
mix.copyDirectory('node_modules/font-awesome/fonts', 'public/fonts');
mix.version();