changes
This commit is contained in:
parent
0c3bbfe18f
commit
0f8cfd3f16
42
app/Events/ClientCaseToTerrain.php
Normal file
42
app/Events/ClientCaseToTerrain.php
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\ClientCase;
|
||||
use App\Models\Segment;
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PresenceChannel;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ClientCaseToTerrain implements ShouldBroadcast
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public ClientCase $clientCase;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*/
|
||||
public function __construct(ClientCase $clientCase)
|
||||
{
|
||||
$this->clientCase = $clientCase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channels the event should broadcast on.
|
||||
*
|
||||
* @return array<int, \Illuminate\Broadcasting\Channel>
|
||||
*/
|
||||
public function broadcastOn(): PrivateChannel
|
||||
{
|
||||
return new PrivateChannel('segments'.$this->clientCase->id);
|
||||
}
|
||||
|
||||
public function broadcastAs(){
|
||||
return 'client_case.terrain.add';
|
||||
}
|
||||
}
|
||||
43
app/Events/ContractToTerrain.php
Normal file
43
app/Events/ContractToTerrain.php
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\Contract;
|
||||
use App\Models\Segment;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ContractToTerrain implements ShouldBroadcast
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public Contract $contract;
|
||||
public Segment $segment;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*/
|
||||
public function __construct(Contract $contract, Segment $segment)
|
||||
{
|
||||
//
|
||||
$this->contract = $contract;
|
||||
$this->segment = $segment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channels the event should broadcast on.
|
||||
*
|
||||
* @return array<int, \Illuminate\Broadcasting\Channel>
|
||||
*/
|
||||
public function broadcastOn(): PrivateChannel
|
||||
{
|
||||
return new PrivateChannel('contracts.'.$this->segment->id);
|
||||
}
|
||||
|
||||
public function broadcastAs(){
|
||||
return 'contract.terrain.add';
|
||||
}
|
||||
}
|
||||
|
|
@ -131,7 +131,14 @@ public function storeActivity(ClientCase $clientCase, Request $request) {
|
|||
]);
|
||||
|
||||
//Create activity
|
||||
$clientCase->activities()->create($attributes);
|
||||
$activity = $clientCase->activities()->create($attributes);
|
||||
|
||||
foreach ($activity->decision->events as $e) {
|
||||
$class = '\\App\\Events\\' . $e->name;
|
||||
event(new $class($clientCase));
|
||||
}
|
||||
|
||||
|
||||
|
||||
return to_route('clientCase.show', $clientCase);
|
||||
|
||||
|
|
@ -156,6 +163,11 @@ public function show(ClientCase $clientCase)
|
|||
'person' => fn($que) => $que->with(['addresses', 'phones'])
|
||||
])->where('active', 1)->findOrFail($clientCase->id);
|
||||
|
||||
$types = [
|
||||
'address_types' => \App\Models\Person\AddressType::all(),
|
||||
'phone_types' => \App\Models\Person\PhoneType::all()
|
||||
];
|
||||
|
||||
return Inertia::render('Cases/Show', [
|
||||
'client' => $case->client()->with('person', fn($q) => $q->with(['addresses', 'phones']))->firstOrFail(),
|
||||
'client_case' => $case,
|
||||
|
|
@ -166,7 +178,8 @@ public function show(ClientCase $clientCase)
|
|||
->orderByDesc('created_at')
|
||||
->paginate(20, ['*'], 'activities'),
|
||||
'contract_types' => \App\Models\ContractType::whereNull('deleted_at')->get(),
|
||||
'actions' => \App\Models\Action::with('decisions')->get()
|
||||
'actions' => \App\Models\Action::with('decisions')->get(),
|
||||
'types' => $types
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,11 @@ public function show(Client $client, Request $request) {
|
|||
->with(['person' => fn($que) => $que->with(['addresses','phones'])])
|
||||
->findOrFail($client->id);
|
||||
|
||||
$types = [
|
||||
'address_types' => \App\Models\Person\AddressType::all(),
|
||||
'phone_types' => \App\Models\Person\PhoneType::all()
|
||||
];
|
||||
|
||||
return Inertia::render('Client/Show', [
|
||||
'client' => $data,
|
||||
'client_cases' => $data->clientCases()
|
||||
|
|
@ -47,6 +52,7 @@ public function show(Client $client, Request $request) {
|
|||
->orderByDesc('created_at')
|
||||
->paginate(15)
|
||||
->withQueryString(),
|
||||
'types' => $types,
|
||||
'filters' => $request->only(['search'])
|
||||
]);
|
||||
}
|
||||
|
|
@ -91,4 +97,9 @@ public function store(Request $request)
|
|||
return to_route('client');
|
||||
|
||||
}
|
||||
|
||||
public function update(Client $client, Request $request) {
|
||||
|
||||
return to_route('client.show', $client);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
use App\Models\Person\Person;
|
||||
use Illuminate\Http\Request;
|
||||
use Inertia\Inertia;
|
||||
|
||||
class PersonController extends Controller
|
||||
{
|
||||
|
|
@ -19,4 +20,91 @@ public function create(Request $request){
|
|||
public function store(Request $request){
|
||||
|
||||
}
|
||||
|
||||
public function update(Person $person, Request $request){
|
||||
$attributes = $request->validate([
|
||||
'full_name' => 'string|max:255',
|
||||
'tax_number' => 'nullable|integer',
|
||||
'social_security_number' => 'nullable|integer',
|
||||
'description' => 'nullable|string|max:500'
|
||||
]);
|
||||
|
||||
$person->update($attributes);
|
||||
|
||||
return response()->json([
|
||||
'person' => [
|
||||
'full_name' => $person->full_name,
|
||||
'tax_number' => $person->tax_number,
|
||||
'social_security_number' => $person->social_security_number,
|
||||
'description' => $person->description
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
public function createAddress(Person $person, Request $request){
|
||||
$attributes = $request->validate([
|
||||
'address' => 'required|string|max:150',
|
||||
'country' => 'nullable|string',
|
||||
'type_id' => 'required|integer|exists:address_types,id',
|
||||
'description' => 'nullable|string|max:125'
|
||||
]);
|
||||
|
||||
$address_id = $person->addresses()->create($attributes)->id;
|
||||
|
||||
return response()->json([
|
||||
'address' => \App\Models\Person\PersonAddress::with(['type'])->findOrFail($address_id)
|
||||
]);
|
||||
}
|
||||
|
||||
public function updateAddress(Person $person, int $address_id, Request $request)
|
||||
{
|
||||
$attributes = $request->validate([
|
||||
'address' => 'required|string|max:150',
|
||||
'country' => 'nullable|string',
|
||||
'type_id' => 'required|integer|exists:address_types,id',
|
||||
'description' => 'nullable|string|max:125'
|
||||
]);
|
||||
|
||||
$address = $person->addresses()->with(['type'])->findOrFail($address_id);
|
||||
|
||||
$address->update($attributes);
|
||||
|
||||
return response()->json([
|
||||
'address' => $address
|
||||
]);
|
||||
}
|
||||
|
||||
public function createPhone(Person $person, Request $request)
|
||||
{
|
||||
$attributes = $request->validate([
|
||||
'nu' => 'required|string|max:50',
|
||||
'country_code' => 'nullable|integer',
|
||||
'type_id' => 'required|integer|exists:phone_types,id',
|
||||
'description' => 'nullable|string|max:125'
|
||||
]);
|
||||
|
||||
$phone_id = $person->phones()->create($attributes)->id;
|
||||
|
||||
return response()->json([
|
||||
'phone' => \App\Models\Person\PersonPhone::with(['type'])->findOrFail($phone_id)
|
||||
]);
|
||||
}
|
||||
|
||||
public function updatePhone(Person $person, int $phone_id, Request $request)
|
||||
{
|
||||
$attributes = $request->validate([
|
||||
'nu' => 'required|string|max:50',
|
||||
'country_code' => 'nullable|integer',
|
||||
'type_id' => 'required|integer|exists:phone_types,id',
|
||||
'description' => 'nullable|string|max:125'
|
||||
]);
|
||||
|
||||
$phone = $person->phones()->with(['type'])->findOrFail($phone_id);
|
||||
|
||||
$phone->update($attributes);
|
||||
|
||||
return response()->json([
|
||||
'phone' => $phone
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,10 +13,10 @@ public function index(Request $request){
|
|||
|
||||
return Inertia::render('Settings/Index', [
|
||||
'actions' => \App\Models\Action::query()
|
||||
->with('decisions', fn($q) => $q->get(['decisions.id']))
|
||||
->with('decisions')
|
||||
->get(),
|
||||
'decisions' => \App\Models\Decision::query()
|
||||
->with('actions', fn($q) => $q->get(['actions.id']))
|
||||
->with('actions')
|
||||
->get()
|
||||
]
|
||||
);
|
||||
|
|
|
|||
41
app/Listeners/AddClientCaseToTerrain.php
Normal file
41
app/Listeners/AddClientCaseToTerrain.php
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Events\ClientCaseToTerrain;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
|
||||
class AddClientCaseToTerrain
|
||||
{
|
||||
/**
|
||||
* Create the event listener.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*/
|
||||
public function handle(ClientCaseToTerrain $event): void
|
||||
{
|
||||
$clientCase = $event->clientCase;
|
||||
$segment = \App\Models\Segment::where('name','terrain')->firstOrFail();
|
||||
|
||||
if( $segment ) {
|
||||
$clientCase->segments()->detach($segment->id);
|
||||
$clientCase->segments()->attach(
|
||||
$segment->id,
|
||||
);
|
||||
|
||||
\Log::info("Added contract to terrain", ['contract_id' => $clientCase->id, 'segment' => $segment->name ]);
|
||||
}
|
||||
}
|
||||
|
||||
public function failed(ClientCaseToTerrain $event, $exception)
|
||||
{
|
||||
\Log::error('Failed to update inventory', ['contract_id' => $event->clientCase->id, 'error' => $exception->getMessage()]);
|
||||
}
|
||||
}
|
||||
37
app/Listeners/AddContractToTerrain.php
Normal file
37
app/Listeners/AddContractToTerrain.php
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Events\ContractToTerrain;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
|
||||
class AddContractToTerrain implements ShouldQueue
|
||||
{
|
||||
/**
|
||||
* Create the event listener.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*/
|
||||
public function handle(ContractToTerrain $event): void
|
||||
{
|
||||
$contract = $event->contract;
|
||||
$segment = $event->segment->where('name', 'terrain')->firstOrFail();
|
||||
|
||||
if($segment) {
|
||||
$contract->segments()->attach($segment->id);
|
||||
//\Log::info("Added contract to terrain", ['contract_id' => $contract->id, 'segment' => $segment->name ]);
|
||||
}
|
||||
}
|
||||
|
||||
public function failed(ContractToTerrain $event, $exception)
|
||||
{
|
||||
//\Log::error('Failed to update inventory', ['contract_id' => $event->contract->id, 'error' => $exception->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Laravel\Scout\Searchable;
|
||||
|
|
@ -47,7 +48,8 @@ public function client(): BelongsTo
|
|||
|
||||
public function person(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(\App\Models\Person\Person::class);
|
||||
return $this->belongsTo(\App\Models\Person\Person::class)
|
||||
->with(['phones', 'addresses']);
|
||||
}
|
||||
|
||||
public function contracts(): HasMany
|
||||
|
|
@ -59,4 +61,8 @@ public function activities(): HasMany
|
|||
{
|
||||
return $this->hasMany(\App\Models\Activity::class);
|
||||
}
|
||||
|
||||
public function segments(): BelongsToMany {
|
||||
return $this->belongsToMany(\App\Models\Segment::class)->withTimestamps();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,15 @@
|
|||
namespace App\Models;
|
||||
|
||||
use App\Traits\Uuid;
|
||||
use Illuminate\Database\Eloquent\Factories\BelongsToManyRelationship;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOneOrManyThrough;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphOne;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Contract extends Model
|
||||
|
|
@ -36,17 +41,16 @@ public function type(): BelongsTo
|
|||
return $this->belongsTo(\App\Models\ContractType::class, 'type_id');
|
||||
}
|
||||
|
||||
public function client(): BelongsTo
|
||||
public function clientCase(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(\App\Models\Person\Person::class, 'client_id');
|
||||
return $this->belongsTo(\App\Models\ClientCase::class)
|
||||
->with(['person']);
|
||||
}
|
||||
|
||||
public function debtor(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(\App\Models\Person\Person::class, 'debtor_id');
|
||||
}
|
||||
|
||||
|
||||
public function segments(): BelongsToMany {
|
||||
return $this->belongsToMany(\App\Models\Segment::class);
|
||||
return $this->belongsToMany(\App\Models\Segment::class)
|
||||
->withPivot('active', 'created_at')
|
||||
->wherePivot('active', true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,9 +4,15 @@
|
|||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
|
||||
class Event extends Model
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\EventFactory> */
|
||||
use HasFactory;
|
||||
|
||||
public function decisions(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(\App\Models\Decision::class);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,14 +76,16 @@ public function phones(): HasMany
|
|||
{
|
||||
return $this->hasMany(\App\Models\Person\PersonPhone::class)
|
||||
->with(['type'])
|
||||
->where('active','=',1);
|
||||
->where('active','=',1)
|
||||
->orderBy('id');
|
||||
}
|
||||
|
||||
public function addresses(): HasMany
|
||||
{
|
||||
return $this->hasMany(\App\Models\Person\PersonAddress::class)
|
||||
->with(['type'])
|
||||
->where('active','=',1);
|
||||
->where('active','=',1)
|
||||
->orderBy('id');
|
||||
}
|
||||
|
||||
public function group(): BelongsTo
|
||||
|
|
|
|||
|
|
@ -14,4 +14,8 @@ class Segment extends Model
|
|||
public function contracts(): BelongsToMany {
|
||||
return $this->belongsToMany(\App\Models\Contract::class);
|
||||
}
|
||||
|
||||
public function clientCase(): BelongsToMany {
|
||||
return $this->belongsToMany(\App\Models\ClientCase::class)->withTimestamps();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('client_case_segment', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignIdFor(\App\Models\ClientCase::class)->constrained()->onDelete('cascade');
|
||||
$table->foreignIdFor(\App\Models\Segment::class)->constrained()->onDelete('cascade');
|
||||
$table->boolean('active')->default(true);
|
||||
$table->softDeletes();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('client_case_segment');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('decision_event', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignIdFor(\App\Models\Decision::class);
|
||||
$table->foreignIdFor(\App\Models\Event::class);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('decision_event');
|
||||
}
|
||||
};
|
||||
|
|
@ -26,7 +26,8 @@ public function run(): void
|
|||
$this->call([
|
||||
PersonSeeder::class,
|
||||
SegmentSeeder::class,
|
||||
ActionSeeder::class
|
||||
ActionSeeder::class,
|
||||
EventSeeder::class
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Event;
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
|
|
@ -12,6 +13,12 @@ class EventSeeder extends Seeder
|
|||
*/
|
||||
public function run(): void
|
||||
{
|
||||
//
|
||||
$events = [
|
||||
[ 'name' => 'client_case.terrain.add', 'options' => json_encode([]) ]
|
||||
];
|
||||
|
||||
foreach($events as $e) {
|
||||
Event::create($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ public function run(): void
|
|||
];
|
||||
|
||||
$personGroups = [
|
||||
[ 'name' => 'naročnik', 'description' => '', 'color_tag' => 'blue-400'],
|
||||
[ 'name' => 'naročnik', 'description' => '', 'color_tag' => 'blue-500'],
|
||||
[ 'name' => 'primer naročnika', 'description' => '', 'color_tag' => 'red-400']
|
||||
];
|
||||
|
||||
|
|
|
|||
21
package-lock.json
generated
21
package-lock.json
generated
|
|
@ -18,7 +18,9 @@
|
|||
"flowbite-vue": "^0.1.6",
|
||||
"lodash": "^4.17.21",
|
||||
"material-design-icons-iconfont": "^6.7.0",
|
||||
"preline": "^2.7.0",
|
||||
"tailwindcss-inner-border": "^0.2.0",
|
||||
"vue-multiselect": "^3.1.0",
|
||||
"vue-search-input": "^1.1.16",
|
||||
"vue3-apexcharts": "^1.7.0",
|
||||
"vuedraggable": "^4.1.0"
|
||||
|
|
@ -2837,6 +2839,15 @@
|
|||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/preline": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/preline/-/preline-2.7.0.tgz",
|
||||
"integrity": "sha512-xMuMVZ7aftBT1/5/3Rb48i/t+LWQfsUjBX7bls4peqS6h5OZTbIgz0N6eMDzuDlOZF3DiSWLehl00oGlAkvovw==",
|
||||
"license": "Licensed under MIT and Preline UI Fair Use License",
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.11.2"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
|
|
@ -3552,6 +3563,16 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vue-multiselect": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-multiselect/-/vue-multiselect-3.1.0.tgz",
|
||||
"integrity": "sha512-+i/fjTqFBpaay9NP+lU7obBeNaw2DdFDFs4mqhsM0aEtKRdvIf7CfREAx2o2B4XDmPrBt1r7x1YCM3BOMLaUgQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 14.18.1",
|
||||
"npm": ">= 6.14.15"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-resize": {
|
||||
"version": "2.0.0-alpha.1",
|
||||
"resolved": "https://registry.npmjs.org/vue-resize/-/vue-resize-2.0.0-alpha.1.tgz",
|
||||
|
|
|
|||
|
|
@ -33,7 +33,9 @@
|
|||
"flowbite-vue": "^0.1.6",
|
||||
"lodash": "^4.17.21",
|
||||
"material-design-icons-iconfont": "^6.7.0",
|
||||
"preline": "^2.7.0",
|
||||
"tailwindcss-inner-border": "^0.2.0",
|
||||
"vue-multiselect": "^3.1.0",
|
||||
"vue-search-input": "^1.1.16",
|
||||
"vue3-apexcharts": "^1.7.0",
|
||||
"vuedraggable": "^4.1.0"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
@import '/node_modules/floating-vue/dist/style.css';
|
||||
@import '/node_modules/vue-search-input/dist/styles.css';
|
||||
@import '/node_modules/vue-multiselect/dist/vue-multiselect.min.css';
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
|
|
|||
197
resources/js/Components/AddressCreateForm.vue
Normal file
197
resources/js/Components/AddressCreateForm.vue
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
<script setup>
|
||||
import { ref, watch } from 'vue';
|
||||
import Drawer from './Drawer.vue';
|
||||
import InputLabel from './InputLabel.vue';
|
||||
import SectionTitle from './SectionTitle.vue';
|
||||
import TextInput from './TextInput.vue';
|
||||
import InputError from './InputError.vue';
|
||||
import PrimaryButton from './PrimaryButton.vue';
|
||||
|
||||
|
||||
|
||||
const props = defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
person: Object,
|
||||
types: Array,
|
||||
edit: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
id: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
});
|
||||
|
||||
const processing = ref(false);
|
||||
const errors = ref({});
|
||||
|
||||
const emit = defineEmits(['close']);
|
||||
|
||||
const close = () => {
|
||||
emit('close');
|
||||
|
||||
setTimeout(() => {
|
||||
errors.value = {};
|
||||
}, 500);
|
||||
}
|
||||
|
||||
const form = ref({
|
||||
address: '',
|
||||
country: '',
|
||||
type_id: props.types[0].id,
|
||||
description: ''
|
||||
});
|
||||
|
||||
const resetForm = () => {
|
||||
form.value = {
|
||||
address: '',
|
||||
country: '',
|
||||
type_id: props.types[0].id,
|
||||
description: ''
|
||||
};
|
||||
}
|
||||
|
||||
const create = async () => {
|
||||
processing.value = true;
|
||||
errors.value = {};
|
||||
|
||||
const data = await axios({
|
||||
method: 'post',
|
||||
url: route('person.address.create', props.person),
|
||||
data: form.value
|
||||
}).then((response) => {
|
||||
props.person.addresses.push(response.data.address);
|
||||
|
||||
processing.value = false;
|
||||
|
||||
close();
|
||||
resetForm();
|
||||
|
||||
}).catch((reason) => {
|
||||
errors.value = reason.response.data.errors;
|
||||
processing.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
const update = async () => {
|
||||
processing.value = true;
|
||||
errors.value = {};
|
||||
|
||||
const data = await axios({
|
||||
method: 'put',
|
||||
url: route('person.address.update', {person: props.person, address_id: props.id}),
|
||||
data: form.value
|
||||
}).then((response) => {
|
||||
console.log(response.data.address)
|
||||
const index = props.person.addresses.findIndex( a => a.id === response.data.address.id );
|
||||
props.person.addresses[index] = response.data.address;
|
||||
|
||||
processing.value = false;
|
||||
|
||||
close();
|
||||
resetForm();
|
||||
|
||||
}).catch((reason) => {
|
||||
errors.value = reason.response.data.errors;
|
||||
processing.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.id,
|
||||
((id) => {
|
||||
if (props.edit && id !== 0){
|
||||
console.log(props.edit)
|
||||
props.person.addresses.filter((a) => {
|
||||
if(a.id === props.id){
|
||||
form.value = {
|
||||
address: a.address,
|
||||
country: a.country,
|
||||
type_id: a.type_id,
|
||||
description: a.description
|
||||
};
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
resetForm();
|
||||
})
|
||||
);
|
||||
|
||||
const callSubmit = () => {
|
||||
if( props.edit ) {
|
||||
update();
|
||||
} else {
|
||||
create();
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Drawer
|
||||
:show="show"
|
||||
@close="close"
|
||||
>
|
||||
<template #title>
|
||||
<span v-if="edit">Spremeni naslov</span>
|
||||
<span v-else>Dodaj novi naslov</span>
|
||||
</template>
|
||||
<template #content>
|
||||
<form @submit.prevent="callSubmit">
|
||||
<SectionTitle class="border-b mb-4">
|
||||
<template #title>
|
||||
Naslov
|
||||
</template>
|
||||
</SectionTitle>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="cr_address" value="Naslov" />
|
||||
<TextInput
|
||||
id="cr_address"
|
||||
ref="cr_addressInput"
|
||||
v-model="form.address"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="address"
|
||||
/>
|
||||
|
||||
<InputError v-if="errors.address !== undefined" v-for="err in errors.address" :message="err" />
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="cr_country" value="Država" />
|
||||
<TextInput
|
||||
id="cr_country"
|
||||
ref="cr_countryInput"
|
||||
v-model="form.country"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="country"
|
||||
/>
|
||||
|
||||
<InputError v-if="errors.address !== undefined" v-for="err in errors.address" :message="err" />
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="cr_type" value="Tip"/>
|
||||
<select
|
||||
class="block w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm"
|
||||
id="cr_type"
|
||||
v-model="form.type_id"
|
||||
>
|
||||
<option v-for="type in types" :key="type.id" :value="type.id">{{ type.name }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex justify-end mt-4">
|
||||
|
||||
<PrimaryButton :class="{ 'opacity-25': processing }" :disabled="processing">
|
||||
Shrani
|
||||
</PrimaryButton>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
</Drawer>
|
||||
</template>
|
||||
17
resources/js/Components/AddressUpdateForm.vue
Normal file
17
resources/js/Components/AddressUpdateForm.vue
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "Test",
|
||||
created() {},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
props: {},
|
||||
methods: {},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
25
resources/js/Components/CusTab.vue
Normal file
25
resources/js/Components/CusTab.vue
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<script setup>
|
||||
import { inject } from 'vue';
|
||||
|
||||
|
||||
defineProps({
|
||||
name: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
title: {
|
||||
stype: String,
|
||||
default: ''
|
||||
}
|
||||
});
|
||||
|
||||
const selected = inject('selected');
|
||||
|
||||
</script>
|
||||
<template>
|
||||
|
||||
<div class="py-4 px-2" role="tabpanel" v-show="selected === name">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
</template>
|
||||
38
resources/js/Components/CusTabs.vue
Normal file
38
resources/js/Components/CusTabs.vue
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<script setup>
|
||||
import { provide, ref, useSlots } from 'vue';
|
||||
|
||||
defineProps({
|
||||
selectedColor: {
|
||||
type: String,
|
||||
default: 'blue-600'
|
||||
}
|
||||
});
|
||||
|
||||
const slots = useSlots();
|
||||
const tabs = ref(slots.default().map((tab) => tab.props ));
|
||||
const selected = ref(tabs.value[0].name);
|
||||
|
||||
provide('selected', selected);
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<div class="text-sm font-medium text-center text-gray-500 border-b border-gray-200 dark:text-gray-400 dark:border-gray-700">
|
||||
<ul class="flex flex-wrap -mb-px">
|
||||
<li class="me-2" v-for="tab in tabs" :key="tab.name">
|
||||
<button
|
||||
@click="selected = tab.name"
|
||||
class="inline-block p-4"
|
||||
:class="{
|
||||
['border-b-2 border-transparent rounded-t-lg hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300']: tab.name !== selected,
|
||||
[`text-${ selectedColor } border-b-2 border-${ selectedColor } rounded-t-lg active dark:text-blue-500 dark:border-${ selectedColor }`]: tab.name === selected
|
||||
}"
|
||||
>
|
||||
{{ tab.title }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="default-tab-content">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,43 +1,189 @@
|
|||
<script setup>
|
||||
import { FwbBadge } from 'flowbite-vue';
|
||||
import { EditIcon, PlusIcon, UserEditIcon } from '@/Utilities/Icons';
|
||||
import CusTab from './CusTab.vue';
|
||||
import CusTabs from './CusTabs.vue';
|
||||
import { provide, ref, watch } from 'vue';
|
||||
import PersonUpdateForm from './PersonUpdateForm.vue';
|
||||
import AddressCreateForm from './AddressCreateForm.vue';
|
||||
import PhoneCreateForm from './PhoneCreateForm.vue';
|
||||
|
||||
|
||||
const props = defineProps({
|
||||
person: Object
|
||||
})
|
||||
person: Object,
|
||||
edit: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
tabColor: {
|
||||
type: String,
|
||||
default: 'blue-600'
|
||||
},
|
||||
types: {
|
||||
type: Object,
|
||||
default: {
|
||||
address_types: [],
|
||||
phone_types: []
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
const drawerUpdatePerson = ref(false);
|
||||
const drawerAddAddress = ref(false);
|
||||
const drawerAddPhone = ref(false);
|
||||
|
||||
const editAddress = ref(false);
|
||||
const editAddressId = ref(0);
|
||||
|
||||
const editPhone = ref(false);
|
||||
const editPhoneId = ref(0);
|
||||
|
||||
const getMainAddress = (adresses) => {
|
||||
const addr = adresses.filter( a => a.type.id === 1 )[0] ?? '';
|
||||
if( addr !== '' ){
|
||||
const country = addr.country !== '' ? ` - ${addr.country}` : '';
|
||||
return addr.address !== '' ? addr.address + country : '';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
const getMainPhone = (phones) => {
|
||||
const pho = phones.filter( a => a.type.id === 1 )[0] ?? '';
|
||||
if( pho !== '' ){
|
||||
const countryCode = pho.country_code !== null ? `+${pho.country_code} ` : '';
|
||||
return pho.nu !== '' ? countryCode + pho.nu: '';
|
||||
}
|
||||
|
||||
return '';
|
||||
|
||||
}
|
||||
|
||||
const openDrawerUpdateClient = () => {
|
||||
drawerUpdatePerson.value = true;
|
||||
}
|
||||
|
||||
const openDrawerAddAddress = (edit = false, id = 0) => {
|
||||
drawerAddAddress.value = true;
|
||||
editAddress.value = edit;
|
||||
editAddressId.value = id;
|
||||
|
||||
}
|
||||
|
||||
const operDrawerAddPhone = (edit = false, id = 0) => {
|
||||
drawerAddPhone.value = true;
|
||||
editPhone.value = edit;
|
||||
editPhoneId.value = id;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="grid grid-rows-* grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-2">
|
||||
<div class="rounded p-2 shadow">
|
||||
<p class="text-xs leading-5 md:text-sm text-gray-500">Nu.</p>
|
||||
<p class="text-sm md:text-base leading-7 text-gray-900">{{ person.nu }}</p>
|
||||
</div>
|
||||
<div class="rounded p-2 shadow">
|
||||
<p class="text-sm leading-5 md:text-sm text-gray-500">Name.</p>
|
||||
<p class="text-sm md:text-base leading-7 text-gray-900">{{ person.full_name }}</p>
|
||||
</div>
|
||||
<div class="rounded p-2 shadow">
|
||||
<p class="text-sm leading-5 md:text-sm text-gray-500">Tax NU.</p>
|
||||
<p class="text-sm md:text-base leading-7 text-gray-900">{{ person.tax_number }}</p>
|
||||
</div>
|
||||
<div class="rounded p-2 shadow">
|
||||
<p class="text-sm leading-5 md:text-sm text-gray-500">Social security NU.</p>
|
||||
<p class="text-sm md:text-base leading-7 text-gray-900">{{ person.social_security_number }}</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="grid grid-rows-* grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-2 mt-1">
|
||||
<div class="rounded p-2 shadow">
|
||||
<p class="text-sm leading-5 md:text-sm text-gray-500">Address</p>
|
||||
<p class="text-sm md:text-base leading-7 text-gray-900">{{ person.main_address }}</p>
|
||||
</div>
|
||||
<div class="rounded p-2 shadow">
|
||||
<p class="text-sm leading-5 md:text-sm text-gray-500">Phone</p>
|
||||
<p class="text-sm md:text-base leading-7 text-gray-900">{{ person.main_phone }}</p>
|
||||
</div>
|
||||
<div class="md:col-span-full lg:col-span-1 rounded p-2 shadow">
|
||||
<p class="text-sm leading-5 md:text-sm text-gray-500">Description</p>
|
||||
<p class="text-sm md:text-base leading-7 text-gray-900">{{ person.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<CusTabs :selected-color="tabColor">
|
||||
<CusTab name="person" title="Oseba">
|
||||
<div class="flex justify-end mb-2">
|
||||
<span class=" border-b-2 border-gray-500 hover:border-gray-800">
|
||||
<button @click="openDrawerUpdateClient"><UserEditIcon size="lg" css="text-gray-500 hover:text-gray-800" /></button>
|
||||
</span>
|
||||
</div>
|
||||
<div class="grid grid-rows-* grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-2">
|
||||
<div class="rounded p-2 shadow">
|
||||
<p class="text-xs leading-5 md:text-sm text-gray-500">Nu.</p>
|
||||
<p class="text-sm md:text-base leading-7 text-gray-900">{{ person.nu }}</p>
|
||||
</div>
|
||||
<div class="rounded p-2 shadow">
|
||||
<p class="text-sm leading-5 md:text-sm text-gray-500">Name.</p>
|
||||
<p class="text-sm md:text-base leading-7 text-gray-900">{{ person.full_name }}</p>
|
||||
</div>
|
||||
<div class="rounded p-2 shadow">
|
||||
<p class="text-sm leading-5 md:text-sm text-gray-500">Tax NU.</p>
|
||||
<p class="text-sm md:text-base leading-7 text-gray-900">{{ person.tax_number }}</p>
|
||||
</div>
|
||||
<div class="rounded p-2 shadow">
|
||||
<p class="text-sm leading-5 md:text-sm text-gray-500">Social security NU.</p>
|
||||
<p class="text-sm md:text-base leading-7 text-gray-900">{{ person.social_security_number }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-rows-* grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-2 mt-1">
|
||||
<div class="rounded p-2 shadow">
|
||||
<p class="text-sm leading-5 md:text-sm text-gray-500">Address</p>
|
||||
<p class="text-sm md:text-base leading-7 text-gray-900">{{ getMainAddress(person.addresses) }}</p>
|
||||
</div>
|
||||
<div class="rounded p-2 shadow">
|
||||
<p class="text-sm leading-5 md:text-sm text-gray-500">Phone</p>
|
||||
<p class="text-sm md:text-base leading-7 text-gray-900">{{ getMainPhone(person.phones) }}</p>
|
||||
</div>
|
||||
<div class="md:col-span-full lg:col-span-1 rounded p-2 shadow">
|
||||
<p class="text-sm leading-5 md:text-sm text-gray-500">Description</p>
|
||||
<p class="text-sm md:text-base leading-7 text-gray-900">{{ person.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</CusTab >
|
||||
<CusTab name="addresses" title="Naslovi">
|
||||
<div class="flex justify-end mb-2">
|
||||
<span class="border-b-2 border-gray-500 hover:border-gray-800">
|
||||
<button><PlusIcon @click="openDrawerAddAddress(false, 0)" size="lg" css="text-gray-500 hover:text-gray-800" /></button>
|
||||
</span>
|
||||
</div>
|
||||
<div class="grid grid-rows-* grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-2 mt-1">
|
||||
<div class="rounded p-2 shadow" v-for="address in person.addresses">
|
||||
<div class="text-sm leading-5 md:text-sm text-gray-500 flex justify-between">
|
||||
<div class="flex ">
|
||||
<FwbBadge type="yellow">{{ address.country }}</FwbBadge>
|
||||
<FwbBadge>{{ address.type.name }}</FwbBadge>
|
||||
</div>
|
||||
<button><EditIcon @click="openDrawerAddAddress(true, address.id)" size="md" css="text-gray-500 hover:text-gray-800" /></button>
|
||||
</div>
|
||||
<p class="text-sm md:text-base leading-7 text-gray-900">{{ address.address }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</CusTab>
|
||||
<CusTab name="phones" title="Telefonske">
|
||||
<div class="flex justify-end mb-2">
|
||||
<span class="border-b-2 border-gray-500 hover:border-gray-800">
|
||||
<button><PlusIcon @click="operDrawerAddPhone(false, 0)" size="lg" css="text-gray-500 hover:text-gray-800" /></button>
|
||||
</span>
|
||||
</div>
|
||||
<div class="grid grid-rows-* grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-2 mt-1">
|
||||
<div class="rounded p-2 shadow" v-for="phone in person.phones">
|
||||
<div class="text-sm leading-5 md:text-sm text-gray-500 flex justify-between">
|
||||
<div class="flex ">
|
||||
<FwbBadge title type="yellow">+{{ phone.country_code }}</FwbBadge>
|
||||
<FwbBadge>{{ phone.type.name }}</FwbBadge>
|
||||
</div>
|
||||
<button><EditIcon @click="operDrawerAddPhone(true, phone.id)" size="md" css="text-gray-500 hover:text-gray-800" /></button>
|
||||
</div>
|
||||
<p class="text-sm md:text-base leading-7 text-gray-900">{{ phone.nu }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</CusTab>
|
||||
<CusTab name="other" title="Drugo">
|
||||
ssss4
|
||||
</CusTab>
|
||||
</CusTabs>
|
||||
<PersonUpdateForm
|
||||
:show="drawerUpdatePerson"
|
||||
@close="drawerUpdatePerson = false"
|
||||
:person="person"
|
||||
/>
|
||||
|
||||
<AddressCreateForm
|
||||
:show="drawerAddAddress"
|
||||
@close="drawerAddAddress = false"
|
||||
:person="person"
|
||||
:types="types.address_types"
|
||||
:id="editAddressId"
|
||||
:edit="editAddress"
|
||||
/>
|
||||
|
||||
<PhoneCreateForm
|
||||
:show="drawerAddPhone"
|
||||
@close="drawerAddPhone = false"
|
||||
:person="person"
|
||||
:types="types.phone_types"
|
||||
:id="editPhoneId"
|
||||
:edit="editPhone"
|
||||
/>
|
||||
|
||||
</template>
|
||||
139
resources/js/Components/PersonUpdateForm.vue
Normal file
139
resources/js/Components/PersonUpdateForm.vue
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
<script setup>
|
||||
import Drawer from '@/Components/Drawer.vue';
|
||||
import InputLabel from '@/Components/InputLabel.vue';
|
||||
import PrimaryButton from '@/Components/PrimaryButton.vue';
|
||||
import SectionTitle from '@/Components/SectionTitle.vue';
|
||||
import TextInput from '@/Components/TextInput.vue';
|
||||
import axios from 'axios';
|
||||
import { inject, onMounted, ref } from 'vue';
|
||||
import InputError from './InputError.vue';
|
||||
|
||||
const props = defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
person: Object
|
||||
});
|
||||
|
||||
const processingUpdate = ref(false);
|
||||
const errors = ref({});
|
||||
|
||||
const emit = defineEmits(['close']);
|
||||
|
||||
const close = () => {
|
||||
emit('close');
|
||||
|
||||
setTimeout(() => {
|
||||
errors.value = {};
|
||||
}, 500);
|
||||
}
|
||||
|
||||
const form = ref({
|
||||
full_name: props.person.full_name,
|
||||
tax_number: props.person.tax_number,
|
||||
social_security_number: props.person.social_security_number,
|
||||
description: props.person.description
|
||||
});
|
||||
|
||||
const updatePerson = () => {
|
||||
processingUpdate.value = true;
|
||||
errors.value = {};
|
||||
|
||||
axios({
|
||||
method: 'put',
|
||||
url: route('person.update', props.person ),
|
||||
data: form.value
|
||||
}).then((response) => {
|
||||
|
||||
props.person.full_name = response.data.person.full_name;
|
||||
props.person.tax_number = response.data.person.tax_number;
|
||||
props.person.social_security_number = response.data.person.social_security_number;
|
||||
props.person.description = response.data.person.description;
|
||||
|
||||
processingUpdate.value = false;
|
||||
close();
|
||||
}).catch((reason) => {
|
||||
console.log(reason.response.data);
|
||||
errors.value = reason.response.data.errors;
|
||||
processingUpdate.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<Drawer
|
||||
:show="show"
|
||||
@close="close"
|
||||
>
|
||||
<template #title>Posodobi {{ person.full_name }}</template>
|
||||
<template #content>
|
||||
<form @submit.prevent="updatePerson">
|
||||
<SectionTitle class="border-b mb-4">
|
||||
<template #title>
|
||||
Oseba
|
||||
</template>
|
||||
</SectionTitle>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="cfulname" value="Naziv" />
|
||||
<TextInput
|
||||
id="cfullname"
|
||||
ref="cfullnameInput"
|
||||
v-model="form.full_name"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="full-name"
|
||||
/>
|
||||
<InputError v-if="errors.full_name !== undefined" v-for="err in errors.full_name" :message="err" />
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="ctaxnumber" value="Davčna" />
|
||||
<TextInput
|
||||
id="ctaxnumber"
|
||||
ref="ctaxnumberInput"
|
||||
v-model="form.tax_number"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="tax-number"
|
||||
/>
|
||||
<InputError v-if="errors.tax_number !== undefined" v-for="err in errors.tax_number" :message="err" />
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="csocialSecurityNumber" value="Matična / Emšo" />
|
||||
<TextInput
|
||||
id="csocialSecurityNumber"
|
||||
ref="csocialSecurityNumberInput"
|
||||
v-model="form.social_security_number"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="social-security-number"
|
||||
/>
|
||||
<InputError v-if="errors.social_security_number !== undefined" v-for="err in errors.social_security_number" :message="err" />
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="cdescription" value="Opis"/>
|
||||
<TextInput
|
||||
id="cdescription"
|
||||
ref="cdescriptionInput"
|
||||
v-model="form.description"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="description"
|
||||
/>
|
||||
<InputError v-if="errors.description !== undefined" v-for="err in errors.description" :message="err" />
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end mt-4">
|
||||
|
||||
<PrimaryButton :class="{ 'opacity-25': processingUpdate }" :disabled="processingUpdate">
|
||||
Shrani
|
||||
</PrimaryButton>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
</Drawer>
|
||||
</template>
|
||||
193
resources/js/Components/PhoneCreateForm.vue
Normal file
193
resources/js/Components/PhoneCreateForm.vue
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
<script setup>
|
||||
import { ref, watch } from 'vue';
|
||||
import Drawer from './Drawer.vue';
|
||||
import InputLabel from './InputLabel.vue';
|
||||
import SectionTitle from './SectionTitle.vue';
|
||||
import TextInput from './TextInput.vue';
|
||||
import InputError from './InputError.vue';
|
||||
import PrimaryButton from './PrimaryButton.vue';
|
||||
import axios from 'axios';
|
||||
|
||||
const props = defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
person: Object,
|
||||
types: Array,
|
||||
edit: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
id: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
});
|
||||
|
||||
const processing = ref(false);
|
||||
const errors = ref({});
|
||||
|
||||
const emit = defineEmits(['close']);
|
||||
|
||||
const close = () => {
|
||||
emit('close');
|
||||
|
||||
setTimeout(() => {
|
||||
errors.value = {};
|
||||
}, 500);
|
||||
}
|
||||
|
||||
const form = ref({
|
||||
nu: '',
|
||||
country_code: 386,
|
||||
type_id: props.types[0].id,
|
||||
description: ''
|
||||
});
|
||||
|
||||
const resetForm = () => {
|
||||
form.value = {
|
||||
nu: '',
|
||||
country_code: 386,
|
||||
type_id: props.types[0].id,
|
||||
description: ''
|
||||
}
|
||||
};
|
||||
|
||||
const create = async () => {
|
||||
processing.value = true;
|
||||
errors.value = {};
|
||||
|
||||
const data = await axios({
|
||||
method: 'post',
|
||||
url: route('person.phone.create', props.person),
|
||||
data: form.value
|
||||
}).then((response) => {
|
||||
props.person.phones.push(response.data.phone);
|
||||
|
||||
processing.value = false;
|
||||
|
||||
close();
|
||||
resetForm();
|
||||
}).catch((reason) => {
|
||||
errors.value = reason.response.data.errors;
|
||||
processing.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const update = async () => {
|
||||
processing.value = true;
|
||||
errors.value = {};
|
||||
|
||||
const data = await axios({
|
||||
method: 'put',
|
||||
url: route('person.phone.update', {person: props.person, phone_id: props.id}),
|
||||
data: form.value
|
||||
}).then((response) => {
|
||||
const index = props.person.phones.findIndex( p => p.id === response.data.phone.id );
|
||||
props.person.phones[index] = response.data.phone;
|
||||
|
||||
processing.value = false;
|
||||
close();
|
||||
resetForm();
|
||||
}).catch((reason) => {
|
||||
errors.value = reason.response.data.errors;
|
||||
processing.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.id,
|
||||
((id) => {
|
||||
if ( id !== 0 && props.edit ){
|
||||
const index = props.person.phones.findIndex( p => p.id === id );
|
||||
form.value.nu = props.person.phones[index].nu;
|
||||
form.value.country_code = props.person.phones[index].country_code;
|
||||
form.value.type_id = props.person.phones[index].type_id;
|
||||
form.value.description = props.person.phones[index].description;
|
||||
return;
|
||||
}
|
||||
|
||||
resetForm();
|
||||
|
||||
})
|
||||
);
|
||||
|
||||
const submit = () => {
|
||||
if( props.edit ) {
|
||||
update();
|
||||
} else {
|
||||
create();
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<Drawer
|
||||
:show="show"
|
||||
@close="close"
|
||||
>
|
||||
<template #title>
|
||||
<span v-if="edit">Spremeni telefon</span>
|
||||
<span v-else>Dodaj novi telefon</span>
|
||||
</template>
|
||||
<template #content>
|
||||
<form @submit.prevent="submit">
|
||||
<SectionTitle class="border-b mb-4">
|
||||
<template #title>
|
||||
Telefon
|
||||
</template>
|
||||
</SectionTitle>
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="pp_nu" value="Številka" />
|
||||
<TextInput
|
||||
id="pp_nu"
|
||||
ref="pp_nuInput"
|
||||
v-model="form.nu"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="nu"
|
||||
/>
|
||||
|
||||
<InputError v-if="errors.nu !== undefined" v-for="err in errors.nu" :message="err" />
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="pp_countrycode" value="Koda države tel." />
|
||||
<select
|
||||
class="block w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm"
|
||||
id="pp_countrycode"
|
||||
v-model="form.country_code"
|
||||
>
|
||||
<option value="386">+386 (Slovenija)</option>
|
||||
<option value="385">+385 (Hrvaška)</option>
|
||||
<option value="39">+39 (Italija)</option>
|
||||
<option value="36">+39 (Madžarska)</option>
|
||||
<option value="43">+43 (Avstrija)</option>
|
||||
<option value="381">+381 (Srbija)</option>
|
||||
<option value="387">+387 (Bosna in Hercegovina)</option>
|
||||
<option value="382">+382 (Črna gora)</option>
|
||||
<!-- ... -->
|
||||
</select>
|
||||
|
||||
<InputError v-if="errors.country_code !== undefined" v-for="err in errors.country_code" :message="err" />
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="pp_type" value="Tip"/>
|
||||
<select
|
||||
class="block w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm"
|
||||
id="pp_type"
|
||||
v-model="form.type_id"
|
||||
>
|
||||
<option v-for="type in types" :key="type.id" :value="type.id">{{ type.name }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex justify-end mt-4">
|
||||
|
||||
<PrimaryButton :class="{ 'opacity-25': processing }" :disabled="processing">
|
||||
Shrani
|
||||
</PrimaryButton>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
</Drawer>
|
||||
</template>
|
||||
17
resources/js/Components/PhoneUpdateForm.vue
Normal file
17
resources/js/Components/PhoneUpdateForm.vue
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "Test",
|
||||
created() {},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
props: {},
|
||||
methods: {},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { computed, onMounted, ref, watch } from 'vue';
|
||||
import { ref } from 'vue';
|
||||
import { Head, Link, router, usePage } from '@inertiajs/vue3';
|
||||
import ApplicationMark from '@/Components/ApplicationMark.vue';
|
||||
import Banner from '@/Components/Banner.vue';
|
||||
|
|
@ -8,66 +8,19 @@ import DropdownLink from '@/Components/DropdownLink.vue';
|
|||
import NavLink from '@/Components/NavLink.vue';
|
||||
import ResponsiveNavLink from '@/Components/ResponsiveNavLink.vue';
|
||||
import Breadcrumbs from '@/Components/Breadcrumbs.vue';
|
||||
import axios from 'axios';
|
||||
import { debounce } from 'lodash';
|
||||
import { FwbButton, FwbInput, FwbListGroup, FwbListGroupItem } from 'flowbite-vue';
|
||||
import { AdjustmentIcon, SearchIcon } from '@/Utilities/Icons';
|
||||
import GlobalSearch from './Partials/GlobalSearch.vue';
|
||||
|
||||
const props = defineProps({
|
||||
title: String,
|
||||
});
|
||||
|
||||
|
||||
const showingNavigationDropdown = ref(false);
|
||||
const querySearchDiv = ref(null);
|
||||
|
||||
const querySearch = ref('');
|
||||
|
||||
const querySearchList = ref(true);
|
||||
const querySearchResult = ref([]);
|
||||
|
||||
const logout = () => {
|
||||
router.post(route('logout'));
|
||||
};
|
||||
|
||||
const onSearchFocus = () => {
|
||||
//if(querySearch.value.length > 0) {
|
||||
querySearchList.value = false;
|
||||
//}
|
||||
}
|
||||
|
||||
const onSearchBlue = () => {
|
||||
setTimeout(() => querySearchList.value = true, 300)
|
||||
}
|
||||
|
||||
const searchDebounce = debounce((value) => {
|
||||
axios.get(
|
||||
route('search'),
|
||||
{
|
||||
params: {
|
||||
query: value,
|
||||
limit: 5,
|
||||
tag: ''
|
||||
}
|
||||
}
|
||||
)
|
||||
.then(function(res) {
|
||||
querySearchResult.value = res.data
|
||||
querySearchList.value = false;
|
||||
console.log(res);
|
||||
})
|
||||
.catch(function(error){
|
||||
console.log(error)
|
||||
})
|
||||
.finally(function(){
|
||||
|
||||
});
|
||||
}, 300);
|
||||
|
||||
watch(querySearch, (value) => {
|
||||
searchDebounce(value);
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -111,47 +64,14 @@ watch(querySearch, (value) => {
|
|||
Nastavitve
|
||||
</NavLink>
|
||||
</div>
|
||||
<div class="hidden space-x-8 sm:-my-px sm:items-center sm:ms-10 sm:flex">
|
||||
<GlobalSearch />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hidden sm:flex sm:items-center sm:ms-6">
|
||||
<!-- Settings Dropdown -->
|
||||
<div>
|
||||
<fwb-input
|
||||
v-model="querySearch"
|
||||
placeholder="Iskalnik..."
|
||||
size="md"
|
||||
@focus="onSearchFocus"
|
||||
@blur="onSearchBlue"
|
||||
@input.stop="true"
|
||||
>
|
||||
<template #prefix>
|
||||
<SearchIcon />
|
||||
</template>
|
||||
|
||||
</fwb-input>
|
||||
<fwb-list-group ref="querySearchDiv" class="absolute" :class="(querySearchList) ? 'hidden' : ''">
|
||||
<fwb-list-group-item class="px-0 flex flex-col">
|
||||
|
||||
<p>Naročniki:</p>
|
||||
<fwb-list-group>
|
||||
<fwb-list-group-item hover v-for="client in querySearchResult.clients">
|
||||
<a :href="route('client.show', {uuid: client.client_uuid})">{{ client.full_name }}</a>
|
||||
</fwb-list-group-item>
|
||||
</fwb-list-group>
|
||||
|
||||
</fwb-list-group-item>
|
||||
<fwb-list-group-item class="px-0 flex flex-col">
|
||||
|
||||
<p>Primeri:</p>
|
||||
<fwb-list-group>
|
||||
<fwb-list-group-item hover v-for="clientCase in querySearchResult.client_cases">
|
||||
<a :href="route('clientCase.show', {uuid: clientCase.case_uuid})">{{ clientCase.full_name }}</a>
|
||||
</fwb-list-group-item>
|
||||
</fwb-list-group>
|
||||
|
||||
</fwb-list-group-item>
|
||||
</fwb-list-group>
|
||||
</div>
|
||||
|
||||
<div class="ms-3 relative">
|
||||
<Dropdown align="right" width="48">
|
||||
<template #trigger>
|
||||
|
|
@ -314,50 +234,13 @@ watch(querySearch, (value) => {
|
|||
</template>
|
||||
</template>
|
||||
</div>
|
||||
<!--div class="px-2 w-full relative">
|
||||
<fwb-input
|
||||
v-model="querySearch"
|
||||
placeholder="Iskalnik..."
|
||||
size="md"
|
||||
@focus="onSearchFocus"
|
||||
@blur="onSearchBlue"
|
||||
@input.stop="true"
|
||||
>
|
||||
<template #prefix>
|
||||
<SearchIcon />
|
||||
</template>
|
||||
|
||||
</fwb-input>
|
||||
<fwb-list-group ref="querySearchDiv" class="absolute px-2 w-full mx-auto" :hidden="querySearchList">
|
||||
<fwb-list-group-item class="px-0 flex flex-col">
|
||||
|
||||
<p>Naročniki:</p>
|
||||
<fwb-list-group class="w-full">
|
||||
<fwb-list-group-item hover v-for="client in querySearchResult.clients">
|
||||
<a :href="route('client.show', {uuid: client.client_uuid})">{{ client.full_name }}</a>
|
||||
</fwb-list-group-item>
|
||||
</fwb-list-group>
|
||||
|
||||
</fwb-list-group-item>
|
||||
<fwb-list-group-item class="px-0 flex flex-col">
|
||||
|
||||
<p>Primeri:</p>
|
||||
<fwb-list-group class="w-full">
|
||||
<fwb-list-group-item hover v-for="clientCase in querySearchResult.client_cases">
|
||||
<a :href="route('clientCase.show', {uuid: clientCase.case_uuid})">{{ clientCase.full_name }}</a>
|
||||
</fwb-list-group-item>
|
||||
</fwb-list-group>
|
||||
|
||||
</fwb-list-group-item>
|
||||
</fwb-list-group>
|
||||
</div-->
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Page Heading -->
|
||||
<header v-if="$slots.header" class="bg-white shadow ">
|
||||
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
|
||||
<header v-if="$slots.header" class="bg-white shadow">
|
||||
<div class="max-w-7xl mx-auto py-4 px-4 sm:px-6 lg:px-8">
|
||||
<Breadcrumbs :breadcrumbs="$page.props.breadcrumbs"></Breadcrumbs>
|
||||
|
||||
</div>
|
||||
|
|
|
|||
72
resources/js/Layouts/Partials/GlobalSearch.vue
Normal file
72
resources/js/Layouts/Partials/GlobalSearch.vue
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
<script setup>
|
||||
import { FwbInput, FwbListGroup, FwbListGroupItem } from 'flowbite-vue';
|
||||
import axios from 'axios';
|
||||
import { debounce } from 'lodash';
|
||||
import { SearchIcon } from '@/Utilities/Icons';
|
||||
import { ref, watch } from 'vue';
|
||||
import Dropdown from '@/Components/Dropdown.vue';
|
||||
import DropdownLink from '@/Components/DropdownLink.vue';
|
||||
|
||||
const props = defineProps({
|
||||
css: String
|
||||
});
|
||||
|
||||
const query = ref('');
|
||||
const result = ref([]);
|
||||
|
||||
const searching = debounce((value) => {
|
||||
axios.get(
|
||||
route('search'),
|
||||
{
|
||||
params: {
|
||||
query: value,
|
||||
limit: 5,
|
||||
tag: ''
|
||||
}
|
||||
}
|
||||
)
|
||||
.then(function(res) {
|
||||
result.value = res.data
|
||||
list.value = false;
|
||||
console.log(res);
|
||||
})
|
||||
.catch(function(error){
|
||||
console.log(error)
|
||||
})
|
||||
.finally(function(){
|
||||
|
||||
});
|
||||
}, 300);
|
||||
|
||||
watch(
|
||||
() => query.value,
|
||||
(val) => searching(val)
|
||||
);
|
||||
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<Dropdown align="left" :contentClasses="['py-1 bg-white lg:w-60']">
|
||||
<template #trigger>
|
||||
<fwb-input
|
||||
v-model="query"
|
||||
placeholder="Iskalnik..."
|
||||
size="sm"
|
||||
class="lg:w-60"
|
||||
>
|
||||
<template #prefix>
|
||||
<SearchIcon />
|
||||
</template>
|
||||
|
||||
</fwb-input>
|
||||
</template>
|
||||
<template #content>
|
||||
<div class="block px-4 py-2 text-xs text-gray-400">Naročnik</div>
|
||||
|
||||
<DropdownLink v-for="client in result.clients" :href="route('client.show', {uuid: client.client_uuid})">{{ client.full_name }}</DropdownLink>
|
||||
<div class="border-t border-gray-200" />
|
||||
<div class="block px-4 py-2 text-xs text-gray-400">Cases</div>
|
||||
<DropdownLink v-for="clientcase in result.client_cases" :href="route('clientCase.show', {uuid: clientcase.case_uuid})">{{ clientcase.full_name }}</DropdownLink>
|
||||
</template>
|
||||
</Dropdown>
|
||||
</template>
|
||||
|
|
@ -1,185 +1,161 @@
|
|||
<script setup>
|
||||
import PersonInfoGrid from '@/Components/PersonInfoGrid.vue';
|
||||
import SectionTitle from '@/Components/SectionTitle.vue';
|
||||
import AppLayout from '@/Layouts/AppLayout.vue';
|
||||
import { Link, useForm } from '@inertiajs/vue3';
|
||||
import { FwbA, FwbButton } from 'flowbite-vue';
|
||||
import { ref } from 'vue';
|
||||
import ContractDrawer from './Partials/ContractDrawer.vue';
|
||||
import ContractTable from './Partials/ContractTable.vue';
|
||||
import ActivityDrawer from './Partials/ActivityDrawer.vue';
|
||||
import ActivityTable from './Partials/ActivityTable.vue';
|
||||
import PersonInfoGrid from "@/Components/PersonInfoGrid.vue";
|
||||
import SectionTitle from "@/Components/SectionTitle.vue";
|
||||
import AppLayout from "@/Layouts/AppLayout.vue";
|
||||
import { FwbButton } from "flowbite-vue";
|
||||
import { onBeforeMount, ref } from "vue";
|
||||
import ContractDrawer from "./Partials/ContractDrawer.vue";
|
||||
import ContractTable from "./Partials/ContractTable.vue";
|
||||
import ActivityDrawer from "./Partials/ActivityDrawer.vue";
|
||||
import ActivityTable from "./Partials/ActivityTable.vue";
|
||||
import { AngleDownIcon, AngleUpIcon } from "@/Utilities/Icons";
|
||||
|
||||
const props = defineProps({
|
||||
client: Object,
|
||||
client_case: Object,
|
||||
contracts: Array,
|
||||
activities: Object,
|
||||
contract_types: Array,
|
||||
actions: Array
|
||||
client: Object,
|
||||
client_case: Object,
|
||||
contracts: Array,
|
||||
activities: Object,
|
||||
contract_types: Array,
|
||||
actions: Array,
|
||||
types: Object
|
||||
});
|
||||
|
||||
console.log(props.actions);
|
||||
|
||||
const getMainAddress = (adresses) => {
|
||||
const addr = adresses.filter( a => a.type.id === 1 )[0] ?? '';
|
||||
const country = addr.country !== '' ? ` - ${addr.country}` : '';
|
||||
return addr.address !== '' ? addr.address + country : '';
|
||||
}
|
||||
|
||||
const getMainPhone = (phones) => {
|
||||
const pho = phones.filter( a => a.type.id === 1 )[0] ?? '';
|
||||
const countryCode = pho.country_code !== null ? `+${pho.country_code} ` : '';
|
||||
return pho.nu !== '' ? countryCode + pho.nu: '';
|
||||
}
|
||||
|
||||
const clientInfo = new Object({
|
||||
nu: props.client.person.nu,
|
||||
full_name: props.client.person.full_name,
|
||||
main_address: getMainAddress(props.client.person.addresses),
|
||||
main_phone: getMainPhone(props.client.person.phones),
|
||||
tax_number: props.client.person.tax_number,
|
||||
social_security_number: props.client.person.social_security_number,
|
||||
description: props.client.person.description
|
||||
});
|
||||
|
||||
const casePersonInfo = new Object({
|
||||
nu: props.client_case.person.nu,
|
||||
full_name: props.client_case.person.full_name,
|
||||
main_address: getMainAddress(props.client_case.person.addresses),
|
||||
main_phone: getMainPhone(props.client_case.person.phones),
|
||||
tax_number: props.client_case.person.tax_number,
|
||||
social_security_number: props.client_case.person.social_security_number,
|
||||
description: props.client_case.person.description
|
||||
});
|
||||
const clientDetails = ref(true);
|
||||
|
||||
//Drawer add new contract
|
||||
|
||||
const drawerCreateContract = ref(false);
|
||||
|
||||
const openDrawerCreateContract = () => {
|
||||
drawerCreateContract.value = true;
|
||||
}
|
||||
drawerCreateContract.value = true;
|
||||
};
|
||||
|
||||
//Drawer add new activity
|
||||
|
||||
const drawerAddActivity = ref(false);
|
||||
|
||||
const openDrawerAddActivity = () => {
|
||||
drawerAddActivity.value = true;
|
||||
}
|
||||
drawerAddActivity.value = true;
|
||||
};
|
||||
|
||||
//Close drawer (all)
|
||||
const closeDrawer = () => {
|
||||
drawerCreateContract.value = false;
|
||||
drawerAddActivity.value = false;
|
||||
}
|
||||
drawerCreateContract.value = false;
|
||||
drawerAddActivity.value = false;
|
||||
};
|
||||
|
||||
const showClientDetails = () => {
|
||||
clientDetails.value = false;
|
||||
};
|
||||
|
||||
const hideClietnDetails = () => {
|
||||
clientDetails.value = true;
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<AppLayout title="Client case">
|
||||
<template #header></template>
|
||||
<div class="pt-12">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4 border-blue-400">
|
||||
<div class="mx-auto max-w-4x1 p-3">
|
||||
<SectionTitle>
|
||||
<template #title>
|
||||
<FwbA class= "hover:text-blue-500" :href="route('client.show', client)">
|
||||
{{ clientInfo.full_name }}
|
||||
</FwbA>
|
||||
</template>
|
||||
|
||||
</SectionTitle>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<AppLayout title="Client case">
|
||||
<template #header></template>
|
||||
<div class="pt-12">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div
|
||||
class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4 border-blue-500"
|
||||
>
|
||||
<div class="mx-auto max-w-4x1 p-3 flex justify-between">
|
||||
<SectionTitle>
|
||||
<template #title>
|
||||
<a class="hover:text-blue-500" :href="route('client.show', client)">
|
||||
{{ client.person.full_name }}
|
||||
</a>
|
||||
</template>
|
||||
</SectionTitle>
|
||||
<button @click="showClientDetails" :hidden="clientDetails ? false : true">
|
||||
<AngleUpIcon />
|
||||
</button>
|
||||
<button :hidden="clientDetails" @click="hideClietnDetails">
|
||||
<AngleDownIcon />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!--div class="pt-1">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4 border-blue-400">
|
||||
<div class="mx-auto max-w-4x1 p-3">
|
||||
<PersonInfoGrid :person="clientInfo" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div-->
|
||||
<div class="pt-6">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4 border-red-400">
|
||||
<div class="mx-auto max-w-4x1 p-3">
|
||||
<SectionTitle>
|
||||
<template #title>
|
||||
Primer - oseba
|
||||
</template>
|
||||
|
||||
</SectionTitle>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-1" :hidden="clientDetails">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div
|
||||
class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4 border-blue-400"
|
||||
>
|
||||
<div class="mx-auto max-w-4x1 p-3">
|
||||
<PersonInfoGrid :types="types" :person="client.person" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-1">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4 border-red-400">
|
||||
<div class="mx-auto max-w-4x1 p-3">
|
||||
<PersonInfoGrid :person="casePersonInfo" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-6">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div
|
||||
class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4 border-red-400"
|
||||
>
|
||||
<div class="mx-auto max-w-4x1 p-3">
|
||||
<SectionTitle>
|
||||
<template #title> Primer - oseba </template>
|
||||
</SectionTitle>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-12">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4">
|
||||
<div class="mx-auto max-w-4x1">
|
||||
<div class="flex justify-between p-3">
|
||||
<SectionTitle>
|
||||
<template #title>
|
||||
Pogodbe
|
||||
</template>
|
||||
</SectionTitle>
|
||||
<FwbButton @click="openDrawerCreateContract">Nova</FwbButton>
|
||||
</div>
|
||||
<ContractTable
|
||||
:client_case="client_case"
|
||||
:contracts="contracts"
|
||||
:contract_types="contract_types"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-1">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div
|
||||
class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4 border-red-400"
|
||||
>
|
||||
<div class="mx-auto max-w-4x1 p-3">
|
||||
<PersonInfoGrid :types="types" tab-color="red-600" :person="client_case.person" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-12 pb-6">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4">
|
||||
<div class="mx-auto max-w-4x1">
|
||||
<div class="flex justify-between p-3">
|
||||
<SectionTitle>
|
||||
<template #title>
|
||||
Aktivnosti
|
||||
</template>
|
||||
</SectionTitle>
|
||||
<FwbButton @click="openDrawerAddActivity">Nova</FwbButton>
|
||||
</div>
|
||||
<ActivityTable
|
||||
:client_case="client_case"
|
||||
:activities="activities"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-12">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4">
|
||||
<div class="mx-auto max-w-4x1">
|
||||
<div class="flex justify-between p-3">
|
||||
<SectionTitle>
|
||||
<template #title> Pogodbe </template>
|
||||
</SectionTitle>
|
||||
<FwbButton @click="openDrawerCreateContract">Nova</FwbButton>
|
||||
</div>
|
||||
<ContractTable
|
||||
:client_case="client_case"
|
||||
:contracts="contracts"
|
||||
:contract_types="contract_types"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</AppLayout>
|
||||
<ContractDrawer
|
||||
:show="drawerCreateContract"
|
||||
@close="closeDrawer"
|
||||
:types="contract_types"
|
||||
:client_case="client_case"
|
||||
/>
|
||||
<ActivityDrawer
|
||||
:show="drawerAddActivity"
|
||||
@close="closeDrawer"
|
||||
:client_case="client_case"
|
||||
:actions="actions"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-12 pb-6">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4">
|
||||
<div class="mx-auto max-w-4x1">
|
||||
<div class="flex justify-between p-3">
|
||||
<SectionTitle>
|
||||
<template #title> Aktivnosti </template>
|
||||
</SectionTitle>
|
||||
<FwbButton @click="openDrawerAddActivity">Nova</FwbButton>
|
||||
</div>
|
||||
<ActivityTable :client_case="client_case" :activities="activities" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AppLayout>
|
||||
<ContractDrawer
|
||||
:show="drawerCreateContract"
|
||||
@close="closeDrawer"
|
||||
:types="contract_types"
|
||||
:client_case="client_case"
|
||||
/>
|
||||
<ActivityDrawer
|
||||
:show="drawerAddActivity"
|
||||
@close="closeDrawer"
|
||||
:client_case="client_case"
|
||||
:actions="actions"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
|||
201
resources/js/Pages/Client/Partials/FormCreateCase.vue
Normal file
201
resources/js/Pages/Client/Partials/FormCreateCase.vue
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
<script setup>
|
||||
import Drawer from '@/Components/Drawer.vue';
|
||||
import PrimaryButton from '@/Components/PrimaryButton.vue';
|
||||
import InputLabel from '@/Components/InputLabel.vue';
|
||||
import TextInput from '@/Components/TextInput.vue';
|
||||
import { useForm } from '@inertiajs/vue3';
|
||||
import SectionTitle from '@/Components/SectionTitle.vue';
|
||||
import ActionMessage from '@/Components/ActionMessage.vue';
|
||||
|
||||
const props = defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
clientUuid: String
|
||||
});
|
||||
|
||||
const emit = defineEmits(['close']);
|
||||
|
||||
const close = () => {
|
||||
emit('close');
|
||||
}
|
||||
|
||||
const Address = {
|
||||
address: '',
|
||||
country: '',
|
||||
type_id: 1
|
||||
}
|
||||
|
||||
const Phone = {
|
||||
nu: '',
|
||||
country_code: '00386',
|
||||
type_id: 1
|
||||
}
|
||||
|
||||
const Person = {
|
||||
first_name: '',
|
||||
last_name: '',
|
||||
full_name: '',
|
||||
tax_number: '',
|
||||
social_security_number: '',
|
||||
description: '',
|
||||
address: Address,
|
||||
phone: Phone
|
||||
}
|
||||
|
||||
const formCreateCase = useForm({
|
||||
client_uuid: props.clientUuid,
|
||||
person: Person
|
||||
});
|
||||
|
||||
const storeCase = () => {
|
||||
formCreateCase.post(route('clientCase.store'), {
|
||||
onSuccess: () => {
|
||||
close();
|
||||
formCreateCase.reset();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<Drawer
|
||||
:show="show"
|
||||
@close="close">
|
||||
|
||||
<template #title>Nova primer</template>
|
||||
<template #content>
|
||||
<form @submit.prevent="storeCase">
|
||||
<SectionTitle class="border-b mb-4">
|
||||
<template #title>
|
||||
Oseba
|
||||
</template>
|
||||
</SectionTitle>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="fullname" value="Naziv"/>
|
||||
<TextInput
|
||||
id="fullname"
|
||||
ref="fullnameInput"
|
||||
v-model="formCreateCase.person.full_name"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="full-name"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="taxnumber" value="Davčna"/>
|
||||
<TextInput
|
||||
id="taxnumber"
|
||||
ref="taxnumberInput"
|
||||
v-model="formCreateCase.tax_number"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="tax-number"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="socialSecurityNumber" value="Matična / Emšo"/>
|
||||
<TextInput
|
||||
id="socialSecurityNumber"
|
||||
ref="socialSecurityNumberInput"
|
||||
v-model="formCreateCase.social_security_number"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="social-security-number"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="address" value="Naslov"/>
|
||||
<TextInput
|
||||
id="address"
|
||||
ref="addressInput"
|
||||
v-model="formCreateCase.person.address.address"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="address"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="addressCountry" value="Država"/>
|
||||
<TextInput
|
||||
id="addressCountry"
|
||||
ref="addressCountryInput"
|
||||
v-model="formCreateCase.person.address.country"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="address-country"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="addressType" value="Vrsta naslova"/>
|
||||
<select
|
||||
class="block w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm"
|
||||
id="addressType"
|
||||
v-model="formCreateCase.person.address.type_id"
|
||||
>
|
||||
<option value="1">Stalni</option>
|
||||
<option value="2">Začasni</option>
|
||||
<!-- ... -->
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="phoneCountyCode" value="Koda države tel."/>
|
||||
<select
|
||||
class="block w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm"
|
||||
id="phoneCountyCode"
|
||||
v-model="formCreateCase.person.phone.country_code"
|
||||
>
|
||||
<option value="00386">+386 (Slovenija)</option>
|
||||
<option value="00385">+385 (Hrvaška)</option>
|
||||
<option value="0039">+39 (Italija)</option>
|
||||
<option value="0036">+39 (Madžarska)</option>
|
||||
<option value="0043">+43 (Avstrija)</option>
|
||||
<option value="00381">+381 (Srbija)</option>
|
||||
<option value="00387">+387 (Bosna in Hercegovina)</option>
|
||||
<option value="00382">+382 (Črna gora)</option>
|
||||
<!-- ... -->
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="phoneNu" value="Telefonska št."/>
|
||||
<TextInput
|
||||
id="phoneNu"
|
||||
ref="phoneNuInput"
|
||||
v-model="formCreateCase.person.phone.nu"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="phone-nu"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="description" value="Opis"/>
|
||||
<TextInput
|
||||
id="description"
|
||||
ref="descriptionInput"
|
||||
v-model="formCreateCase.description"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="description"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex justify-end mt-4">
|
||||
<ActionMessage :on="formCreateCase.recentlySuccessful" class="me-3">
|
||||
Shranjeno.
|
||||
</ActionMessage>
|
||||
|
||||
<PrimaryButton :class="{ 'opacity-25': formCreateCase.processing }" :disabled="formCreateCase.processing">
|
||||
Shrani
|
||||
</PrimaryButton>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
</Drawer>
|
||||
</template>
|
||||
118
resources/js/Pages/Client/Partials/FormUpdateClient.vue
Normal file
118
resources/js/Pages/Client/Partials/FormUpdateClient.vue
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
<script setup>
|
||||
import ActionMessage from '@/Components/ActionMessage.vue';
|
||||
import Drawer from '@/Components/Drawer.vue';
|
||||
import InputLabel from '@/Components/InputLabel.vue';
|
||||
import PrimaryButton from '@/Components/PrimaryButton.vue';
|
||||
import SectionTitle from '@/Components/SectionTitle.vue';
|
||||
import TextInput from '@/Components/TextInput.vue';
|
||||
import { useForm } from '@inertiajs/vue3';
|
||||
import { onMounted } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
client: Object
|
||||
});
|
||||
|
||||
|
||||
const emit = defineEmits(['close']);
|
||||
|
||||
const close = () => {
|
||||
emit('close');
|
||||
}
|
||||
|
||||
const form = useForm({
|
||||
person: props.client.person
|
||||
});
|
||||
|
||||
const updateClient = () => {
|
||||
form.put(route('person.update', props.client.person ), {
|
||||
onSuccess: () => {
|
||||
close();
|
||||
form.reset();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
console.log(props.client)
|
||||
});
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<Drawer
|
||||
:show="show"
|
||||
@close="close"
|
||||
>
|
||||
<template #title>Posodobi {{ client.person.full_name }}</template>
|
||||
<template #content>
|
||||
<form @submit.prevent="updateClient">
|
||||
<SectionTitle class="border-b mb-4">
|
||||
<template #title>
|
||||
Oseba
|
||||
</template>
|
||||
</SectionTitle>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="cfulname" value="Naziv" />
|
||||
<TextInput
|
||||
id="cfullname"
|
||||
ref="cfullnameInput"
|
||||
v-model="form.person.full_name"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="full-name"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="ctaxnumber" value="Davčna" />
|
||||
<TextInput
|
||||
id="ctaxnumber"
|
||||
ref="ctaxnumberInput"
|
||||
v-model="form.person.tax_number"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="tax-number"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="csocialSecurityNumber" value="Matična / Emšo" />
|
||||
<TextInput
|
||||
id="csocialSecurityNumber"
|
||||
ref="csocialSecurityNumberInput"
|
||||
v-model="form.person.social_security_number"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="social-security-number"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="cdescription" value="Opis"/>
|
||||
<TextInput
|
||||
id="cdescription"
|
||||
ref="cdescriptionInput"
|
||||
v-model="form.description"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="description"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end mt-4">
|
||||
<ActionMessage :on="form.recentlySuccessful" class="me-3">
|
||||
Shranjeno.
|
||||
</ActionMessage>
|
||||
|
||||
<PrimaryButton :class="{ 'opacity-25': form.processing }" :disabled="form.processing">
|
||||
Shrani
|
||||
</PrimaryButton>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
</Drawer>
|
||||
</template>
|
||||
|
|
@ -3,52 +3,20 @@ import AppLayout from '@/Layouts/AppLayout.vue';
|
|||
import List from '@/Components/List.vue';
|
||||
import ListItem from '@/Components/ListItem.vue';
|
||||
import PrimaryButton from '@/Components/PrimaryButton.vue';
|
||||
import Drawer from '@/Components/Drawer.vue';
|
||||
import InputLabel from '@/Components/InputLabel.vue';
|
||||
import TextInput from '@/Components/TextInput.vue';
|
||||
import { ref } from 'vue';
|
||||
import { Link, useForm } from '@inertiajs/vue3';
|
||||
import ActionMessage from '@/Components/ActionMessage.vue';
|
||||
import { Link } from '@inertiajs/vue3';
|
||||
import SectionTitle from '@/Components/SectionTitle.vue';
|
||||
import PersonInfoGrid from '@/Components/PersonInfoGrid.vue';
|
||||
import Pagination from '@/Components/Pagination.vue';
|
||||
import SearchInput from '@/Components/SearchInput.vue';
|
||||
import FormCreateCase from './Partials/FormCreateCase.vue';
|
||||
|
||||
const props = defineProps({
|
||||
client: Object,
|
||||
client_cases: Object,
|
||||
urlPrev: String,
|
||||
filters: Object
|
||||
});
|
||||
|
||||
console.log(props.client_cases)
|
||||
|
||||
const Address = {
|
||||
address: '',
|
||||
country: '',
|
||||
type_id: 1
|
||||
}
|
||||
|
||||
const Phone = {
|
||||
nu: '',
|
||||
country_code: '00386',
|
||||
type_id: 1
|
||||
}
|
||||
|
||||
const Person = {
|
||||
first_name: '',
|
||||
last_name: '',
|
||||
full_name: '',
|
||||
tax_number: '',
|
||||
social_security_number: '',
|
||||
description: '',
|
||||
address: Address,
|
||||
phone: Phone
|
||||
}
|
||||
|
||||
const formCreateCase = useForm({
|
||||
client_uuid: props.client.uuid,
|
||||
person: Person
|
||||
filters: Object,
|
||||
types: Object
|
||||
});
|
||||
|
||||
const search = {
|
||||
|
|
@ -65,42 +33,6 @@ const openDrawerCreateCase = () => {
|
|||
drawerCreateCase.value = true;
|
||||
}
|
||||
|
||||
const closeDrawer = () => {
|
||||
drawerCreateCase.value = false
|
||||
}
|
||||
|
||||
const getMainAddress = (adresses) => {
|
||||
const addr = adresses.filter( a => a.type.id === 1 )[0] ?? '';
|
||||
const country = addr.country !== '' ? ` - ${addr.country}` : '';
|
||||
return addr.address !== '' ? addr.address + country : '';
|
||||
}
|
||||
|
||||
const getMainPhone = (phones) => {
|
||||
const pho = phones.filter( a => a.type.id === 1 )[0] ?? '';
|
||||
const countryCode = pho.country_code !== null ? `+${pho.country_code} ` : '';
|
||||
return pho.nu !== '' ? countryCode + pho.nu: '';
|
||||
}
|
||||
const clientInfo = new Object({
|
||||
nu: props.client.person.nu,
|
||||
full_name: props.client.person.full_name,
|
||||
main_address: getMainAddress(props.client.person.addresses),
|
||||
main_phone: getMainPhone(props.client.person.phones),
|
||||
tax_number: props.client.person.tax_number,
|
||||
social_security_number: props.client.person.social_security_number,
|
||||
description: props.client.person.description
|
||||
});
|
||||
|
||||
const storeCase = () => {
|
||||
formCreateCase.post(route('clientCase.store'), {
|
||||
onSuccess: () => {
|
||||
closeDrawer();
|
||||
formCreateCase.reset();
|
||||
console.log(props.client_cases)
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -109,12 +41,11 @@ const storeCase = () => {
|
|||
<div class="pt-12">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4 border-blue-400">
|
||||
<div class="mx-auto max-w-4x1 p-3">
|
||||
<div class="mx-auto max-w-4x1 p-3 flex justify-between">
|
||||
<SectionTitle>
|
||||
<template #title>
|
||||
{{ client.person.full_name }}
|
||||
</template>
|
||||
|
||||
</SectionTitle>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -123,8 +54,8 @@ const storeCase = () => {
|
|||
<div class="pt-1">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4 border-blue-400">
|
||||
<div class="mx-auto max-w-4x1 p-3">
|
||||
<PersonInfoGrid :person="clientInfo"></PersonInfoGrid>
|
||||
<div class="mx-auto max-w-4x1 px-2">
|
||||
<PersonInfoGrid :types="types" :person="client.person"></PersonInfoGrid>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -162,141 +93,9 @@ const storeCase = () => {
|
|||
</div>
|
||||
</div>
|
||||
</AppLayout>
|
||||
<Drawer
|
||||
:show="drawerCreateCase"
|
||||
@close="drawerCreateCase = false">
|
||||
|
||||
<template #title>Nova primer</template>
|
||||
<template #content>
|
||||
<form @submit.prevent="storeCase">
|
||||
<SectionTitle class="border-b mb-4">
|
||||
<template #title>
|
||||
Oseba
|
||||
</template>
|
||||
</SectionTitle>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="fullname" value="Naziv"/>
|
||||
<TextInput
|
||||
id="fullname"
|
||||
ref="fullnameInput"
|
||||
v-model="formCreateCase.person.full_name"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="full-name"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="taxnumber" value="Davčna"/>
|
||||
<TextInput
|
||||
id="taxnumber"
|
||||
ref="taxnumberInput"
|
||||
v-model="formCreateCase.tax_number"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="tax-number"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="socialSecurityNumber" value="Matična / Emšo"/>
|
||||
<TextInput
|
||||
id="socialSecurityNumber"
|
||||
ref="socialSecurityNumberInput"
|
||||
v-model="formCreateCase.social_security_number"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="social-security-number"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="address" value="Naslov"/>
|
||||
<TextInput
|
||||
id="address"
|
||||
ref="addressInput"
|
||||
v-model="formCreateCase.person.address.address"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="address"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="addressCountry" value="Država"/>
|
||||
<TextInput
|
||||
id="addressCountry"
|
||||
ref="addressCountryInput"
|
||||
v-model="formCreateCase.person.address.country"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="address-country"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="addressType" value="Vrsta naslova"/>
|
||||
<select
|
||||
class="block w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm"
|
||||
id="addressType"
|
||||
v-model="formCreateCase.person.address.type_id"
|
||||
>
|
||||
<option value="1">Stalni</option>
|
||||
<option value="2">Začasni</option>
|
||||
<!-- ... -->
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="phoneCountyCode" value="Koda države tel."/>
|
||||
<select
|
||||
class="block w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm"
|
||||
id="phoneCountyCode"
|
||||
v-model="formCreateCase.person.phone.country_code"
|
||||
>
|
||||
<option value="00386">+386 (Slovenija)</option>
|
||||
<option value="00385">+385 (Hrvaška)</option>
|
||||
<option value="0039">+39 (Italija)</option>
|
||||
<option value="0036">+39 (Madžarska)</option>
|
||||
<option value="0043">+43 (Avstrija)</option>
|
||||
<option value="00381">+381 (Srbija)</option>
|
||||
<option value="00387">+387 (Bosna in Hercegovina)</option>
|
||||
<option value="00382">+382 (Črna gora)</option>
|
||||
<!-- ... -->
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="phoneNu" value="Telefonska št."/>
|
||||
<TextInput
|
||||
id="phoneNu"
|
||||
ref="phoneNuInput"
|
||||
v-model="formCreateCase.person.phone.nu"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="phone-nu"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="description" value="Opis"/>
|
||||
<TextInput
|
||||
id="description"
|
||||
ref="descriptionInput"
|
||||
v-model="formCreateCase.description"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="description"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex justify-end mt-4">
|
||||
<ActionMessage :on="formCreateCase.recentlySuccessful" class="me-3">
|
||||
Shranjeno.
|
||||
</ActionMessage>
|
||||
|
||||
<PrimaryButton :class="{ 'opacity-25': formCreateCase.processing }" :disabled="formCreateCase.processing">
|
||||
Shrani
|
||||
</PrimaryButton>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
</Drawer>
|
||||
<FormCreateCase
|
||||
:show="drawerCreateCase"
|
||||
@close="drawerCreateCase = false"
|
||||
:client-uuid="client?.uuid"
|
||||
/>
|
||||
</template>
|
||||
|
|
@ -6,10 +6,12 @@ import { LinkOptions as C_LINK, TableColumn as C_TD, TableRow as C_TR} from '@/S
|
|||
|
||||
const props = defineProps({
|
||||
chart: Object,
|
||||
people: Array
|
||||
people: Array,
|
||||
terrain: Array
|
||||
});
|
||||
|
||||
console.log(props.people)
|
||||
|
||||
console.log(props.terrain)
|
||||
|
||||
|
||||
const tablePersonHeader = [
|
||||
|
|
@ -18,14 +20,21 @@ const tablePersonHeader = [
|
|||
C_TD.make('Skupina', 'header')
|
||||
];
|
||||
|
||||
let tablePersonBody = [];
|
||||
const tblTerrainHead = [
|
||||
C_TD.make('Št.', 'header'),
|
||||
C_TD.make('Naziv', 'header'),
|
||||
C_TD.make('Začetek', 'header')
|
||||
];
|
||||
|
||||
let tablePersonBody = [];
|
||||
let tblTerrainBody = [];
|
||||
|
||||
const getRoute = (person) => {
|
||||
if( person.client ){
|
||||
return {route: 'client.show', options: person.client};
|
||||
}
|
||||
|
||||
return {route: 'clientCase.show', options: person.client_case};
|
||||
return {route: 'clientCase.show', options: person};
|
||||
}
|
||||
|
||||
props.people.forEach((p) => {
|
||||
|
|
@ -34,12 +43,25 @@ props.people.forEach((p) => {
|
|||
const cols = [
|
||||
C_TD.make(Number(p.nu), 'body', {}, C_LINK.make(forLink.route, forLink.options, `font-bold hover:text-${p.group.color_tag}`)),
|
||||
C_TD.make(p.full_name, 'body'),
|
||||
C_TD.make(p.group.name)
|
||||
C_TD.make(p.group.added_segment, 'body')
|
||||
];
|
||||
|
||||
tablePersonBody.push(C_TR.make(cols, {class: `border-l-4 border-${p.group.color_tag}`}))
|
||||
});
|
||||
|
||||
props.terrain.forEach((t) => {
|
||||
const forLink = getRoute(t);
|
||||
const startDate = new Date(t.added_segment).toLocaleDateString('de');
|
||||
|
||||
const cols = [
|
||||
C_TD.make(t.person.nu, 'body', {}, C_LINK.make(forLink.route, forLink.options, `font-bold hover:text-red-400`)),
|
||||
C_TD.make(t.person.full_name, 'body'),
|
||||
C_TD.make(startDate, 'body')
|
||||
];
|
||||
|
||||
tblTerrainBody.push(C_TR.make(cols, {class: `border-l-4 border-red-400`}));
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -67,7 +89,7 @@ props.people.forEach((p) => {
|
|||
Seznam primerov za terensko delo
|
||||
</template>
|
||||
</SectionTitle>
|
||||
<BasicTable :header="tablePersonHeader" :body="tablePersonBody"></BasicTable>
|
||||
<BasicTable :header="tblTerrainHead" :body="tblTerrainBody"></BasicTable>
|
||||
</div>
|
||||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
|
||||
<SectionTitle class="p-4">
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ const activeTab = ref('actions')
|
|||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
|
||||
<fwb-tabs v-model="activeTab" variant="underline" >
|
||||
<fwb-tab name="actions" title="Actions">
|
||||
<ActionTable :actions="actions" />
|
||||
<ActionTable :actions="actions" :decisions="decisions" />
|
||||
</fwb-tab>
|
||||
<fwb-tab name="decisions" title="Decisions">
|
||||
<DecisionTable :decisions="decisions" />
|
||||
|
|
|
|||
|
|
@ -1,12 +1,69 @@
|
|||
<script setup>
|
||||
import { FwbTable, FwbTableBody, FwbTableHead, FwbTableHeadCell, FwbTableCell, FwbTableRow } from 'flowbite-vue';
|
||||
import { EditIcon, TrashBinIcon } from '@/Utilities/Icons';
|
||||
import Drawer from '@/Components/Drawer.vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useForm } from '@inertiajs/vue3';
|
||||
import InputLabel from '@/Components/InputLabel.vue';
|
||||
import TextInput from '@/Components/TextInput.vue';
|
||||
import Multiselect from 'vue-multiselect';
|
||||
|
||||
|
||||
const props = defineProps({
|
||||
actions: Array
|
||||
actions: Array,
|
||||
decisions: Array
|
||||
});
|
||||
|
||||
const drawerEdit = ref(false);
|
||||
|
||||
const selectOptions = ref([]);
|
||||
|
||||
const selectValue = ref([]);
|
||||
|
||||
const form = useForm({
|
||||
id: 0,
|
||||
name: '',
|
||||
color_tag: '',
|
||||
decisions: []
|
||||
});
|
||||
|
||||
const openEditDrawer = (item) => {
|
||||
form.id = item.id;
|
||||
form.name = item.name;
|
||||
form.color_tag = item.color_tag;
|
||||
drawerEdit.value = true;
|
||||
console.log(item.decisions);
|
||||
|
||||
item.decisions.forEach((d) => {
|
||||
selectValue.value.push({
|
||||
name: d.name,
|
||||
code: d.name.substring(0,2).toLowerCase() + d.id
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
const closeEditDrawer = () => {
|
||||
form.reset();
|
||||
|
||||
drawerEdit.value = false;
|
||||
}
|
||||
|
||||
const onColorPickerChange = () => {
|
||||
console.log(form.color_tag);
|
||||
}
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
props.decisions.forEach((d) => {
|
||||
selectOptions.value.push({
|
||||
name: d.name,
|
||||
code: d.name.substring(0,2).toLowerCase() + d.id
|
||||
});
|
||||
});
|
||||
|
||||
console.log(selectOptions.value);
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
<template>
|
||||
|
|
@ -27,10 +84,63 @@ const props = defineProps({
|
|||
<fwb-table-cell>{{ act.color_tag }}</fwb-table-cell>
|
||||
<fwb-table-cell>{{ act.decisions.length }}</fwb-table-cell>
|
||||
<fwb-table-cell>
|
||||
<button><EditIcon /></button>
|
||||
<button><TrashBinIcon /></button>
|
||||
<button @click="openEditDrawer(act)"><EditIcon /></button>
|
||||
</fwb-table-cell>
|
||||
</fwb-table-row>
|
||||
</fwb-table-body>
|
||||
</fwb-table>
|
||||
<Drawer
|
||||
:show="drawerEdit"
|
||||
@close="closeEditDrawer"
|
||||
>
|
||||
|
||||
<template #title>
|
||||
<span>Spremeni akcijo</span>
|
||||
</template>
|
||||
<template #content>
|
||||
<form @submit.prevent="">
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="name" value="Ime"/>
|
||||
<TextInput
|
||||
id="name"
|
||||
ref="nameInput"
|
||||
v-model="form.name"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
autocomplete="name"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="colorTag" value="Barva"/>
|
||||
<div class="mt-1 w-full border flex p-1">
|
||||
<TextInput
|
||||
id="colorTag"
|
||||
ref="colorTagInput"
|
||||
v-model="form.color_tag"
|
||||
@change="onColorPickerChange"
|
||||
type="color"
|
||||
class="mr-2"
|
||||
autocomplete="color-tag"
|
||||
/>
|
||||
<span>{{ form.color_tag }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="decisions" value="Odločitve"/>
|
||||
<multiselect
|
||||
id="decisions"
|
||||
ref="decisionsSelect"
|
||||
v-model="selectValue"
|
||||
:options="selectOptions"
|
||||
:multiple="true"
|
||||
track-by="code"
|
||||
:taggable="true"
|
||||
placeholder="Dodaj odločitev"
|
||||
label="name"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
</Drawer>
|
||||
</template>
|
||||
|
|
@ -1,13 +1,37 @@
|
|||
|
||||
import { ref } from "vue";
|
||||
|
||||
const Icon = {
|
||||
props: {
|
||||
css: {
|
||||
type: String,
|
||||
default: 'text-gray-800'
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: 'md'
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
defineSize: (val) => {
|
||||
let size = '';
|
||||
|
||||
switch(val){
|
||||
case 'xs':
|
||||
size = 'w-3 h-3';
|
||||
break;
|
||||
case 'sm':
|
||||
size = 'w-4 h-4';
|
||||
break;
|
||||
case 'lg':
|
||||
size = 'w-6 h-6';
|
||||
break;
|
||||
default:
|
||||
size = 'w-5 h-5';
|
||||
break;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const AddressBookIcon = {
|
||||
|
|
@ -15,52 +39,98 @@ const AddressBookIcon = {
|
|||
setup: () => {
|
||||
console.log(this.props)
|
||||
},
|
||||
template: `<svg class="w-6 h-6 dark:text-white" :class="css" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
template: `<svg class="dark:text-white" :class="[defineSize(size),css]" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 6H5m2 3H5m2 3H5m2 3H5m2 3H5m11-1a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2M7 3h11a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1Zm8 7a2 2 0 1 1-4 0 2 2 0 0 1 4 0Z"/>
|
||||
</svg>`
|
||||
};
|
||||
|
||||
const AlignCenterIcon = {
|
||||
__proto__: Icon,
|
||||
template: `<svg class="w-6 h-6 dark:text-white" :class="css" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
template: `<svg class=" dark:text-white" :class="css" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 6h8M6 10h12M8 14h8M6 18h12"/>
|
||||
</svg>`
|
||||
}
|
||||
|
||||
const EditIcon = {
|
||||
__proto__: Icon,
|
||||
template: `<svg class="w-6 h-6 dark:text-white" :class="css" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
template: `<svg class="dark:text-white" :class="[defineSize(size),css]" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m14.304 4.844 2.852 2.852M7 7H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-4.5m2.409-9.91a2.017 2.017 0 0 1 0 2.853l-6.844 6.844L8 14l.713-3.565 6.844-6.844a2.015 2.015 0 0 1 2.852 0Z"/>
|
||||
</svg>`
|
||||
}
|
||||
|
||||
const TrashBinIcon = {
|
||||
__proto__: Icon,
|
||||
template: `<svg class="w-6 h-6 dark:text-white" :class="css" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
|
||||
template: `<svg class=" dark:text-white" :class="[defineSize(size),css]" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path fill-rule="evenodd" d="M8.586 2.586A2 2 0 0 1 10 2h4a2 2 0 0 1 2 2v2h3a1 1 0 1 1 0 2v12a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V8a1 1 0 0 1 0-2h3V4a2 2 0 0 1 .586-1.414ZM10 6h4V4h-4v2Zm1 4a1 1 0 1 0-2 0v8a1 1 0 1 0 2 0v-8Zm4 0a1 1 0 1 0-2 0v8a1 1 0 1 0 2 0v-8Z" clip-rule="evenodd"/>
|
||||
</svg>`
|
||||
}
|
||||
|
||||
const SearchIcon = {
|
||||
__proto__: Icon,
|
||||
template: `<svg aria-hidden="true" class="w-5 h-5 text-gray-500 dark:text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
template: `<svg aria-hidden="true" class="text-gray-500 dark:text-gray-400" :class="[defineSize(size),css]" fill="none" stroke="currentColor" width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />
|
||||
</svg>`
|
||||
}
|
||||
|
||||
const AdjustmentIcon = {
|
||||
__proto__: Icon,
|
||||
template: `<svg class="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
template: `<svg class="text-gray-500 dark:text-white" :class="[defineSize(size),css]" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" :class="[defineSize(size),css]" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M20 6H10m0 0a2 2 0 1 0-4 0m4 0a2 2 0 1 1-4 0m0 0H4m16 6h-2m0 0a2 2 0 1 0-4 0m4 0a2 2 0 1 1-4 0m0 0H4m16 6H10m0 0a2 2 0 1 0-4 0m4 0a2 2 0 1 1-4 0m0 0H4"/>
|
||||
</svg>
|
||||
`
|
||||
}
|
||||
|
||||
const AngleDownIcon = {
|
||||
__proto__: Icon,
|
||||
template: `<svg class="text-gray-500 dark:text-white" :class="[defineSize(size),css]" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m19 9-7 7-7-7"/>
|
||||
</svg>
|
||||
`
|
||||
}
|
||||
|
||||
const AngleUpIcon = {
|
||||
__proto__: Icon,
|
||||
template: `<svg class="text-gray-800 dark:text-white" :class="[defineSize(size),css]" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m5 15 7-7 7 7"/>
|
||||
</svg>
|
||||
`
|
||||
}
|
||||
|
||||
const UserEditIcon = {
|
||||
__proto__: Icon,
|
||||
template: `<svg class="dark:text-white" :class="[defineSize(size),css]" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" stroke-width="2" d="M7 19H5a1 1 0 0 1-1-1v-1a3 3 0 0 1 3-3h1m4-6a3 3 0 1 1-6 0 3 3 0 0 1 6 0Zm7.441 1.559a1.907 1.907 0 0 1 0 2.698l-6.069 6.069L10 19l.674-3.372 6.07-6.07a1.907 1.907 0 0 1 2.697 0Z"/>
|
||||
</svg>
|
||||
`
|
||||
}
|
||||
|
||||
|
||||
const CirclePlusIcon = {
|
||||
__proto__: Icon,
|
||||
template: `<svg class="dark:text-white" :class="[defineSize(size),css]" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 7.757v8.486M7.757 12h8.486M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"/>
|
||||
</svg>
|
||||
`
|
||||
}
|
||||
|
||||
const PlusIcon = {
|
||||
__proto__: Icon,
|
||||
template: `<svg class="dark:text-white" :class="[defineSize(size),css]" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h14m-7 7V5"/>
|
||||
</svg>
|
||||
`
|
||||
}
|
||||
|
||||
export {
|
||||
AddressBookIcon,
|
||||
AlignCenterIcon,
|
||||
EditIcon,
|
||||
TrashBinIcon,
|
||||
SearchIcon,
|
||||
AdjustmentIcon
|
||||
AdjustmentIcon,
|
||||
AngleDownIcon,
|
||||
AngleUpIcon,
|
||||
UserEditIcon,
|
||||
CirclePlusIcon,
|
||||
PlusIcon
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
|
|||
import { ZiggyVue } from '../../vendor/tightenco/ziggy';
|
||||
import VueApexCharts from 'vue3-apexcharts';
|
||||
import VueDatePicker from '@vuepic/vue-datepicker';
|
||||
import '@vuepic/vue-datepicker/dist/main.css'
|
||||
import '@vuepic/vue-datepicker/dist/main.css';
|
||||
|
||||
const appName = import.meta.env.VITE_APP_NAME || 'Laravel';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
|
||||
use App\Charts\ExampleChart;
|
||||
use App\Http\Controllers\PersonController;
|
||||
use App\Http\Controllers\ClientCaseContoller;
|
||||
use App\Http\Controllers\ClientController;
|
||||
use App\Http\Controllers\ContractController;
|
||||
|
|
@ -21,7 +22,7 @@
|
|||
])->group(function () {
|
||||
Route::get('/dashboard', function () {
|
||||
$chart = new ExampleChart(new LarapexChart());
|
||||
$people = Person::with(['group','type', 'client', 'clientCase'])
|
||||
$people = Person::with(['group', 'type', 'client', 'clientCase'])
|
||||
->where([
|
||||
['active','=',1],
|
||||
])
|
||||
|
|
@ -29,11 +30,21 @@
|
|||
->orderByDesc('created_at')
|
||||
->get();
|
||||
|
||||
$terrain = \App\Models\ClientCase::join('client_case_segment', 'client_cases.id', '=', 'client_case_segment.client_case_id')
|
||||
->select('client_cases.*', 'client_case_segment.created_at as added_segment')
|
||||
->where('client_case_segment.segment_id', '=', 2)
|
||||
->where('client_case_segment.active', '=', true)
|
||||
->orderByDesc('client_case_segment.created_at')
|
||||
->limit(10)
|
||||
->with('person')
|
||||
->get();
|
||||
|
||||
return Inertia::render(
|
||||
'Dashboard',
|
||||
[
|
||||
'chart' => $chart->build(),
|
||||
'people' => $people
|
||||
'people' => $people,
|
||||
'terrain' => $terrain
|
||||
]
|
||||
);
|
||||
})->name('dashboard');
|
||||
|
|
@ -45,24 +56,6 @@
|
|||
Route::get('search', function(Request $request) {
|
||||
|
||||
if( !empty($request->input('query')) ) {
|
||||
|
||||
/*$clients = App\Models\Client::search($request->input('query'))
|
||||
->query( function($builder) use($request){
|
||||
$builder->leftJoin('person', 'clients.person_id', '=', 'person.id')
|
||||
->leftJoin('person_addresses', 'person_addresses.person_id', '=', 'person.id')
|
||||
->select('clients.*', 'person.full_name as person_fullname')
|
||||
->limit($request->input('limit'));
|
||||
})
|
||||
->get();
|
||||
|
||||
$clientCases = App\Models\ClientCase::search($request->input('query'))
|
||||
->query(function($builder) use($request){
|
||||
$builder->join('person', 'client_cases.person_id', '=', 'person.id')
|
||||
->select('client_cases.*', 'person.full_name as person_fullname')
|
||||
->limit($request->input('limit'));
|
||||
})
|
||||
->get();*/
|
||||
|
||||
|
||||
$clients = App\Models\Person\Person::search($request->input('query'))
|
||||
->query(function($builder) use($request): void {
|
||||
|
|
@ -95,10 +88,17 @@
|
|||
return [];
|
||||
})->name('search');
|
||||
|
||||
//person
|
||||
Route::put('person/{person:uuid}', [PersonController::class, 'update'])->name('person.update');
|
||||
Route::post('person/{person:uuid}/address', [PersonController::class, 'createAddress'])->name('person.address.create');
|
||||
Route::put('person/{person:uuid}/address/{address_id}', [PersonController::class, 'updateAddress'])->name('person.address.update');
|
||||
Route::post('person/{person:uuid}/phone', [PersonController::class, 'createPhone'])->name('person.phone.create');
|
||||
Route::put('person/{person:uuid}/phone/{phone_id}', [PersonController::class, 'updatePhone'])->name('person.phone.update');
|
||||
//client
|
||||
Route::get('clients', [ClientController::class, 'index'])->name('client');
|
||||
Route::get('clients/{client:uuid}', [ClientController::class, 'show'])->name('client.show');
|
||||
Route::post('clients', [ClientController::class, 'store'])->name('client.store');
|
||||
Route::put('clients/{client:uuid}', [ClientController::class, 'update'])->name('client.update');
|
||||
|
||||
//client-case
|
||||
Route::get('client-cases', [ClientCaseContoller::class, 'index'])->name('clientCase');
|
||||
|
|
@ -113,4 +113,14 @@
|
|||
|
||||
Route::get('settings', [SettingController::class, 'index'])->name('settings');
|
||||
|
||||
//types
|
||||
|
||||
Route::get('types/address', function(Request $request){
|
||||
$types = App\Models\Person\AddressType::all();
|
||||
|
||||
return response()->json([
|
||||
'types' => $types
|
||||
]);
|
||||
})->name('types.address');
|
||||
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user