mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-24 02:14:21 -04:00
Access module relations from parent (#2553)
* Refactor JS directory structure * Access Module relations from Parent entity
This commit is contained in:
parent
bdb0f43d33
commit
95f1d24b8f
9
Modules/Notes/Config/relations.php
Normal file
9
Modules/Notes/Config/relations.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'client' => [
|
||||
'notes' => function ($self) {
|
||||
return $self->hasMany('Modules\Notes\Entities\Note');
|
||||
}
|
||||
],
|
||||
];
|
@ -17,8 +17,10 @@ class NotesTable extends Migration
|
||||
$table->increments('id');
|
||||
$table->unsignedInteger('client_id')->index();
|
||||
$table->unsignedInteger('user_id')->index();
|
||||
$table->unsignedInteger('company_id')->index();
|
||||
$table->string('description');
|
||||
$table->timestamps();
|
||||
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
|
||||
$table->foreign('client_id')->references('id')->on('clients')->onDelete('cascade');
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
});
|
||||
|
@ -6,13 +6,24 @@ use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Note extends Model
|
||||
{
|
||||
/*
|
||||
protected $guarded = [
|
||||
'id',
|
||||
];
|
||||
*/
|
||||
protected $fillable = ["description"];
|
||||
|
||||
|
||||
protected $table = 'notes';
|
||||
|
||||
public function client()
|
||||
{
|
||||
$this->hasOne(App\Models\Client::class);
|
||||
return $this->hasOne(App\Models\Client::class);
|
||||
}
|
||||
|
||||
public function notes()
|
||||
{
|
||||
return $this->hasMany(Note::class);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Routing\Controller;
|
||||
use Modules\Notes\Entities\Note;
|
||||
use Nwidart\Modules\Facades\Module;
|
||||
use Yajra\DataTables\Facades\DataTables;
|
||||
use Yajra\DataTables\Html\Builder;
|
||||
|
||||
class NotesController extends Controller
|
||||
@ -58,7 +58,7 @@ class NotesController extends Controller
|
||||
]);
|
||||
|
||||
$data['html'] = $html;
|
||||
|
||||
|
||||
return view('notes::index', $data);
|
||||
}
|
||||
|
||||
|
28
Modules/Notes/Http/ViewComposers/ClientEditComposer.php
Normal file
28
Modules/Notes/Http/ViewComposers/ClientEditComposer.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Notes\Http\ViewComposers;
|
||||
|
||||
use App\Utils\Traits\UserSessionAttributes;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class ClientEditComposer
|
||||
{
|
||||
use UserSessionAttributes;
|
||||
|
||||
/**
|
||||
* Bind data to the view.
|
||||
*
|
||||
* @param View $view
|
||||
* @return void
|
||||
*/
|
||||
public function compose(View $view)
|
||||
{
|
||||
$data = $view->getData();
|
||||
|
||||
$view->with('notes::edit', $this->clientEditData);
|
||||
}
|
||||
|
||||
private function clientEditData()
|
||||
{
|
||||
|
||||
}
|
@ -46,8 +46,11 @@ class NotesServiceProvider extends ServiceProvider
|
||||
protected function registerConfig()
|
||||
{
|
||||
$this->publishes([
|
||||
__DIR__.'/../Config/config.php' => config_path('notes.php'),
|
||||
__DIR__.'/../Config/config.php' => config_path('modules.notes' . '.php'),
|
||||
], 'config');
|
||||
|
||||
$this->mergeConfigFrom(__DIR__.'/../Config/relations.php', 'modules.relations');
|
||||
|
||||
$this->mergeConfigFrom(
|
||||
__DIR__.'/../Config/config.php', 'notes'
|
||||
);
|
||||
|
7
Modules/Notes/Resources/lang/en/texts.php
Normal file
7
Modules/Notes/Resources/lang/en/texts.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'new_note' => 'New Note',
|
||||
];
|
||||
|
||||
?>
|
13
Modules/Notes/Resources/views/edit.blade.php
Normal file
13
Modules/Notes/Resources/views/edit.blade.php
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
<div class="container-fluid">
|
||||
@if($client)
|
||||
<span>{{ $client->name }} </span>
|
||||
@endif
|
||||
|
||||
<ul>
|
||||
@foreach($client->notes()->get() as $note)
|
||||
<li> {{ $note->description }} </li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
@ -1,3 +1,4 @@
|
||||
@extends('layouts.master', ['header' => $header])
|
||||
|
||||
@section('head')
|
||||
@parent
|
||||
@ -13,15 +14,23 @@
|
||||
{{ Breadcrumbs::render('clients') }}
|
||||
|
||||
<div class="container-fluid">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<button class="btn btn-primary btn-lg pull-right">{{ trans('notes::texts.new_note') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="ui-view">
|
||||
<div class="animated fadeIn">
|
||||
<div class="row col-lg-12 card">
|
||||
<div class="animated fadeIn" style="padding-top:20px;">
|
||||
<div class="row col-md-12 card">
|
||||
|
||||
{!! $html->table() !!}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
@endsection
|
||||
|
@ -7,13 +7,20 @@ use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class BaseModel extends Model
|
||||
{
|
||||
/*
|
||||
public function setIdAttribute($value)
|
||||
public function __call($method, $params)
|
||||
{
|
||||
$hashids = new Hashids(); //decoded output is _always_ an array.
|
||||
$hashed_id_array = $hashids->decode($value);
|
||||
$entity = strtolower(class_basename($this));
|
||||
|
||||
$this->attributes['id'] = strtolower($hashed_id_array[0]);
|
||||
if ($entity) {
|
||||
$configPath = "modules.relations.$entity.$method";
|
||||
|
||||
if (config()->has($configPath)) {
|
||||
$function = config()->get($configPath);
|
||||
|
||||
return $function($this);
|
||||
}
|
||||
}
|
||||
|
||||
return parent::__call($method, $params);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
34904
public/js/client-edit.js
vendored
34904
public/js/client-edit.js
vendored
File diff suppressed because one or more lines are too long
15256
public/js/client_create.js
vendored
15256
public/js/client_create.js
vendored
File diff suppressed because one or more lines are too long
15256
public/js/client_create.min.js
vendored
15256
public/js/client_create.min.js
vendored
File diff suppressed because one or more lines are too long
19741
public/js/client_edit.js
vendored
19741
public/js/client_edit.js
vendored
File diff suppressed because it is too large
Load Diff
19741
public/js/client_edit.min.js
vendored
19741
public/js/client_edit.min.js
vendored
File diff suppressed because it is too large
Load Diff
12588
public/js/coreui.js
vendored
12588
public/js/coreui.js
vendored
File diff suppressed because one or more lines are too long
12588
public/js/coreui.min.js
vendored
12588
public/js/coreui.min.js
vendored
File diff suppressed because one or more lines are too long
11560
public/js/localization.js
vendored
11560
public/js/localization.js
vendored
File diff suppressed because one or more lines are too long
11560
public/js/localization.min.js
vendored
11560
public/js/localization.min.js
vendored
File diff suppressed because one or more lines are too long
13112
public/js/ninja.js
vendored
13112
public/js/ninja.js
vendored
File diff suppressed because it is too large
Load Diff
13112
public/js/ninja.min.js
vendored
13112
public/js/ninja.min.js
vendored
File diff suppressed because it is too large
Load Diff
13112
public/js/vendor/app.js
vendored
13112
public/js/vendor/app.js
vendored
File diff suppressed because it is too large
Load Diff
9
resources/js/app.js
vendored
9
resources/js/app.js
vendored
@ -1,9 +0,0 @@
|
||||
|
||||
/**
|
||||
* First we will load all of this project's JavaScript dependencies which
|
||||
* includes Vue and other libraries. It is a great starting point when
|
||||
* building robust, powerful web applications using Vue and Laravel.
|
||||
*/
|
||||
|
||||
require('./bootstrap');
|
||||
|
@ -1,24 +0,0 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card card-default">
|
||||
<div class="card-header">Example Component</div>
|
||||
|
||||
<div class="card-body">
|
||||
I'm an example component.
|
||||
{{ trans('texts.clients')}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
mounted() {
|
||||
console.log('Component mounted.')
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,37 +0,0 @@
|
||||
/* Allows us to use our native translation easily using {{ trans() }} syntax */
|
||||
//const _ = require('lodash');
|
||||
import * as _ from "lodash"
|
||||
declare var i18n;
|
||||
|
||||
import Vue from 'vue';
|
||||
import axios from 'axios';
|
||||
|
||||
// import Toastr
|
||||
import Toastr from 'vue-toastr';
|
||||
// import toastr scss file: need webpack sass-loader
|
||||
require('vue-toastr/src/vue-toastr.scss');
|
||||
// Register vue component
|
||||
Vue.component('vue-toastr',Toastr);
|
||||
|
||||
Vue.prototype.trans = string => _.get(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
|
||||
* or customize the JavaScript scaffolding to fit your unique needs.
|
||||
*/
|
||||
Vue.component('example-component', require('../../components/ExampleComponent.vue'));
|
||||
Vue.component('client-edit', require('../../components/client/ClientEdit.vue'));
|
||||
Vue.component('client-address', require('../../components/client/ClientAddress.vue'));
|
||||
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({
|
||||
el: '#client_e'
|
||||
});
|
||||
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
//import * as Vue from 'vue';
|
||||
/* Allows us to use our native translation easily using {{ trans() }} syntax */
|
||||
//const _ = require('lodash');
|
||||
import * as _ from "lodash"
|
||||
declare var i18n;
|
||||
|
||||
import Vue from 'vue';
|
||||
import axios from 'axios';
|
||||
import Form from '../utils/form';
|
||||
import Client from '../models/client-model';
|
||||
|
||||
// import Toastr
|
||||
import Toastr from 'vue-toastr';
|
||||
@ -11,67 +13,24 @@ require('vue-toastr/src/vue-toastr.scss');
|
||||
// Register vue component
|
||||
Vue.component('vue-toastr',Toastr);
|
||||
|
||||
declare var client_object: any;
|
||||
declare var hashed_id: string;
|
||||
Vue.prototype.trans = string => _.get(i18n, string);
|
||||
|
||||
new Vue({
|
||||
el : '#client_edit',
|
||||
data: function () {
|
||||
return {
|
||||
form: new Form(<Client>client_object)
|
||||
}
|
||||
},
|
||||
mounted(this: any) {
|
||||
//console.log('mounted')
|
||||
},
|
||||
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.form.contacts.indexOf(contact);
|
||||
this.form.contacts.splice(index, 1);
|
||||
},
|
||||
add(this: any){
|
||||
this.form.contacts.push({first_name: '', last_name: '', email: '', phone: '', id: 0});
|
||||
window.scrollTo(0, document.body.scrollHeight || document.documentElement.scrollHeight);
|
||||
this.$nextTick(() => {
|
||||
let index = this.form.contacts.length - 1;
|
||||
let input = this.$refs.first_name[index];
|
||||
input.focus();
|
||||
});
|
||||
},
|
||||
onSubmit() {
|
||||
this.form.put('/clients/' + hashed_id)
|
||||
.then(response => this.$root.$refs.toastr.s("Saved client"))
|
||||
.catch(error => {
|
||||
/**
|
||||
* Next, we will create a fresh Vue application instance and attach it to
|
||||
* the page. Then, you may begin adding components to this application
|
||||
* or customize the JavaScript scaffolding to fit your unique needs.
|
||||
*/
|
||||
Vue.component('client-edit', require('../components/client/ClientEdit.vue'));
|
||||
Vue.component('client-address', require('../components/client/ClientAddress.vue'));
|
||||
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'));
|
||||
|
||||
this.$root.$refs.toastr.e("Error saving client");
|
||||
|
||||
window.onload = function () {
|
||||
|
||||
});
|
||||
},
|
||||
copy(type: any) {
|
||||
if(type.includes('copy_billing')){
|
||||
this.form.shipping_address1 = this.form.address1;
|
||||
this.form.shipping_address2 = this.form.address2;
|
||||
this.form.shipping_city = this.form.city;
|
||||
this.form.shipping_state = this.form.state;
|
||||
this.form.shipping_postal_code = this.form.postal_code;
|
||||
this.form.shipping_country_id = this.form.country_id;
|
||||
}else {
|
||||
this.form.address1 = this.form.shipping_address1;
|
||||
this.form.address2 = this.form.shipping_address2;
|
||||
this.form.city = this.form.shipping_city;
|
||||
this.form.state = this.form.shipping_state;
|
||||
this.form.postal_code = this.form.shipping_postal_code;
|
||||
this.form.country_id = this.form.shipping_country_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
const app = new Vue({
|
||||
el: '#client_edit'
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -57,8 +57,8 @@
|
||||
|
||||
import Vue from 'vue';
|
||||
import axios from 'axios';
|
||||
import Form from '../../src/utils/form';
|
||||
import Client from '../../src/models/client-model';
|
||||
import Form from '../../utils/form';
|
||||
import Client from '../../models/client-model';
|
||||
|
||||
export default {
|
||||
data: function () {
|
@ -1,7 +1,7 @@
|
||||
@extends('layouts.master', ['header' => $header])
|
||||
|
||||
@section('body')
|
||||
<main class="main" id="client_e">
|
||||
<main class="main" id="client_edit">
|
||||
|
||||
<!-- Breadcrumb-->
|
||||
{{ Breadcrumbs::render('clients.edit', $client) }}
|
||||
@ -16,10 +16,6 @@
|
||||
<a class="nav-link active show" id="pills-home-tab" data-toggle="pill" href="#pills-home" role="tab" aria-controls="pills-home" aria-selected="true"><i class="icon-user"></i> {{ trans('texts.client') }}</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="pills-settings-tab" data-toggle="pill" href="#pills-settings" role="tab" aria-controls="pills-settings" aria-selected="false"><i class="icon-settings"></i> {{ trans('texts.settings') }}</a>
|
||||
</li>
|
||||
|
||||
@foreach($pills as $pill)
|
||||
|
||||
<li class="nav-item">
|
||||
@ -27,6 +23,11 @@
|
||||
</li>
|
||||
|
||||
@endforeach
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="pills-settings-tab" data-toggle="pill" href="#pills-settings" role="tab" aria-controls="pills-settings" aria-selected="false"><i class="icon-settings"></i> {{ trans('texts.settings') }}</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<div class="tab-content" id="pills-tabContent">
|
||||
@ -40,7 +41,9 @@
|
||||
@foreach($pills as $pill)
|
||||
|
||||
<div class="tab-pane fade" id="pills-{{ $pill['alias'] }}" role="tabpanel" aria-labelledby="pills-{{ $pill['alias'] }}-tab">
|
||||
{{$pill['name']}}
|
||||
|
||||
@include($pill['alias'] . '::.edit')
|
||||
|
||||
</div>
|
||||
|
||||
@endforeach
|
||||
@ -56,6 +59,6 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script defer src=" {{ mix('/js/client-edit.js') }}"></script>
|
||||
<script defer src=" {{ mix('/js/client_edit.min.js') }}"></script>
|
||||
|
||||
@endsection
|
@ -14,9 +14,15 @@
|
||||
{{ Breadcrumbs::render('clients') }}
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<button class="btn btn-primary btn-lg pull-right">{{ trans('texts.new_client') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="ui-view">
|
||||
<div class="animated fadeIn">
|
||||
<div class="row col-lg-12 card">
|
||||
<div class="row col-md-12 card">
|
||||
|
||||
{!! $html->table() !!}
|
||||
|
||||
|
0
storage/app/.gitignore
vendored
Normal file → Executable file
0
storage/app/.gitignore
vendored
Normal file → Executable file
0
storage/app/public/.gitignore
vendored
Normal file → Executable file
0
storage/app/public/.gitignore
vendored
Normal file → Executable file
0
storage/framework/.gitignore
vendored
Normal file → Executable file
0
storage/framework/.gitignore
vendored
Normal file → Executable file
0
storage/framework/cache/.gitignore
vendored
Normal file → Executable file
0
storage/framework/cache/.gitignore
vendored
Normal file → Executable file
0
storage/framework/sessions/.gitignore
vendored
Normal file → Executable file
0
storage/framework/sessions/.gitignore
vendored
Normal file → Executable file
0
storage/framework/testing/.gitignore
vendored
Normal file → Executable file
0
storage/framework/testing/.gitignore
vendored
Normal file → Executable file
0
storage/framework/views/.gitignore
vendored
Normal file → Executable file
0
storage/framework/views/.gitignore
vendored
Normal file → Executable file
0
storage/logs/.gitignore
vendored
Normal file → Executable file
0
storage/logs/.gitignore
vendored
Normal file → Executable file
4
webpack.mix.js
vendored
4
webpack.mix.js
vendored
@ -28,14 +28,12 @@ mix.webpackConfig({
|
||||
});
|
||||
|
||||
mix.js('resources/js/src/client/client_edit.ts', 'public/js');
|
||||
mix.js('resources/js/src/c/client-edit.ts', 'public/js');
|
||||
mix.js('resources/js/src/client/client_create.ts', 'public/js');
|
||||
mix.js('resources/js/src/settings/localization.ts', 'public/js');
|
||||
mix.js('resources/js/app.js', 'public/js/vendor');
|
||||
mix.js('node_modules/@coreui/coreui/dist/js/coreui.js', 'public/js');
|
||||
|
||||
mix.scripts([
|
||||
'public/js/vendor/app.js'
|
||||
'js/src/bootstrap.js'
|
||||
], 'public/js/ninja.js');
|
||||
|
||||
mix.minify('public/js/ninja.js');
|
||||
|
Loading…
x
Reference in New Issue
Block a user