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
|
//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);
|
return to_route('clientCase.show', $clientCase);
|
||||||
|
|
||||||
|
|
@ -156,6 +163,11 @@ public function show(ClientCase $clientCase)
|
||||||
'person' => fn($que) => $que->with(['addresses', 'phones'])
|
'person' => fn($que) => $que->with(['addresses', 'phones'])
|
||||||
])->where('active', 1)->findOrFail($clientCase->id);
|
])->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', [
|
return Inertia::render('Cases/Show', [
|
||||||
'client' => $case->client()->with('person', fn($q) => $q->with(['addresses', 'phones']))->firstOrFail(),
|
'client' => $case->client()->with('person', fn($q) => $q->with(['addresses', 'phones']))->firstOrFail(),
|
||||||
'client_case' => $case,
|
'client_case' => $case,
|
||||||
|
|
@ -166,7 +178,8 @@ public function show(ClientCase $clientCase)
|
||||||
->orderByDesc('created_at')
|
->orderByDesc('created_at')
|
||||||
->paginate(20, ['*'], 'activities'),
|
->paginate(20, ['*'], 'activities'),
|
||||||
'contract_types' => \App\Models\ContractType::whereNull('deleted_at')->get(),
|
'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'])])
|
->with(['person' => fn($que) => $que->with(['addresses','phones'])])
|
||||||
->findOrFail($client->id);
|
->findOrFail($client->id);
|
||||||
|
|
||||||
|
$types = [
|
||||||
|
'address_types' => \App\Models\Person\AddressType::all(),
|
||||||
|
'phone_types' => \App\Models\Person\PhoneType::all()
|
||||||
|
];
|
||||||
|
|
||||||
return Inertia::render('Client/Show', [
|
return Inertia::render('Client/Show', [
|
||||||
'client' => $data,
|
'client' => $data,
|
||||||
'client_cases' => $data->clientCases()
|
'client_cases' => $data->clientCases()
|
||||||
|
|
@ -47,6 +52,7 @@ public function show(Client $client, Request $request) {
|
||||||
->orderByDesc('created_at')
|
->orderByDesc('created_at')
|
||||||
->paginate(15)
|
->paginate(15)
|
||||||
->withQueryString(),
|
->withQueryString(),
|
||||||
|
'types' => $types,
|
||||||
'filters' => $request->only(['search'])
|
'filters' => $request->only(['search'])
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
@ -91,4 +97,9 @@ public function store(Request $request)
|
||||||
return to_route('client');
|
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 App\Models\Person\Person;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Inertia\Inertia;
|
||||||
|
|
||||||
class PersonController extends Controller
|
class PersonController extends Controller
|
||||||
{
|
{
|
||||||
|
|
@ -19,4 +20,91 @@ public function create(Request $request){
|
||||||
public function store(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', [
|
return Inertia::render('Settings/Index', [
|
||||||
'actions' => \App\Models\Action::query()
|
'actions' => \App\Models\Action::query()
|
||||||
->with('decisions', fn($q) => $q->get(['decisions.id']))
|
->with('decisions')
|
||||||
->get(),
|
->get(),
|
||||||
'decisions' => \App\Models\Decision::query()
|
'decisions' => \App\Models\Decision::query()
|
||||||
->with('actions', fn($q) => $q->get(['actions.id']))
|
->with('actions')
|
||||||
->get()
|
->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\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Laravel\Scout\Searchable;
|
use Laravel\Scout\Searchable;
|
||||||
|
|
@ -47,7 +48,8 @@ public function client(): BelongsTo
|
||||||
|
|
||||||
public function person(): 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
|
public function contracts(): HasMany
|
||||||
|
|
@ -59,4 +61,8 @@ public function activities(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(\App\Models\Activity::class);
|
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;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Traits\Uuid;
|
use App\Traits\Uuid;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\BelongsToManyRelationship;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
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;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
class Contract extends Model
|
class Contract extends Model
|
||||||
|
|
@ -36,17 +41,16 @@ public function type(): BelongsTo
|
||||||
return $this->belongsTo(\App\Models\ContractType::class, 'type_id');
|
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 {
|
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\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
|
|
||||||
class Event extends Model
|
class Event extends Model
|
||||||
{
|
{
|
||||||
/** @use HasFactory<\Database\Factories\EventFactory> */
|
/** @use HasFactory<\Database\Factories\EventFactory> */
|
||||||
use HasFactory;
|
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)
|
return $this->hasMany(\App\Models\Person\PersonPhone::class)
|
||||||
->with(['type'])
|
->with(['type'])
|
||||||
->where('active','=',1);
|
->where('active','=',1)
|
||||||
|
->orderBy('id');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addresses(): HasMany
|
public function addresses(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(\App\Models\Person\PersonAddress::class)
|
return $this->hasMany(\App\Models\Person\PersonAddress::class)
|
||||||
->with(['type'])
|
->with(['type'])
|
||||||
->where('active','=',1);
|
->where('active','=',1)
|
||||||
|
->orderBy('id');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function group(): BelongsTo
|
public function group(): BelongsTo
|
||||||
|
|
|
||||||
|
|
@ -14,4 +14,8 @@ class Segment extends Model
|
||||||
public function contracts(): BelongsToMany {
|
public function contracts(): BelongsToMany {
|
||||||
return $this->belongsToMany(\App\Models\Contract::class);
|
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([
|
$this->call([
|
||||||
PersonSeeder::class,
|
PersonSeeder::class,
|
||||||
SegmentSeeder::class,
|
SegmentSeeder::class,
|
||||||
ActionSeeder::class
|
ActionSeeder::class,
|
||||||
|
EventSeeder::class
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace Database\Seeders;
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Models\Event;
|
||||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||||
use Illuminate\Database\Seeder;
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
|
|
@ -12,6 +13,12 @@ class EventSeeder extends Seeder
|
||||||
*/
|
*/
|
||||||
public function run(): void
|
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 = [
|
$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']
|
[ '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",
|
"flowbite-vue": "^0.1.6",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"material-design-icons-iconfont": "^6.7.0",
|
"material-design-icons-iconfont": "^6.7.0",
|
||||||
|
"preline": "^2.7.0",
|
||||||
"tailwindcss-inner-border": "^0.2.0",
|
"tailwindcss-inner-border": "^0.2.0",
|
||||||
|
"vue-multiselect": "^3.1.0",
|
||||||
"vue-search-input": "^1.1.16",
|
"vue-search-input": "^1.1.16",
|
||||||
"vue3-apexcharts": "^1.7.0",
|
"vue3-apexcharts": "^1.7.0",
|
||||||
"vuedraggable": "^4.1.0"
|
"vuedraggable": "^4.1.0"
|
||||||
|
|
@ -2837,6 +2839,15 @@
|
||||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/proxy-from-env": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
"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": {
|
"node_modules/vue-resize": {
|
||||||
"version": "2.0.0-alpha.1",
|
"version": "2.0.0-alpha.1",
|
||||||
"resolved": "https://registry.npmjs.org/vue-resize/-/vue-resize-2.0.0-alpha.1.tgz",
|
"resolved": "https://registry.npmjs.org/vue-resize/-/vue-resize-2.0.0-alpha.1.tgz",
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,9 @@
|
||||||
"flowbite-vue": "^0.1.6",
|
"flowbite-vue": "^0.1.6",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"material-design-icons-iconfont": "^6.7.0",
|
"material-design-icons-iconfont": "^6.7.0",
|
||||||
|
"preline": "^2.7.0",
|
||||||
"tailwindcss-inner-border": "^0.2.0",
|
"tailwindcss-inner-border": "^0.2.0",
|
||||||
|
"vue-multiselect": "^3.1.0",
|
||||||
"vue-search-input": "^1.1.16",
|
"vue-search-input": "^1.1.16",
|
||||||
"vue3-apexcharts": "^1.7.0",
|
"vue3-apexcharts": "^1.7.0",
|
||||||
"vuedraggable": "^4.1.0"
|
"vuedraggable": "^4.1.0"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
@import '/node_modules/floating-vue/dist/style.css';
|
@import '/node_modules/floating-vue/dist/style.css';
|
||||||
@import '/node_modules/vue-search-input/dist/styles.css';
|
@import '/node_modules/vue-search-input/dist/styles.css';
|
||||||
|
@import '/node_modules/vue-multiselect/dist/vue-multiselect.min.css';
|
||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@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>
|
<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({
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="grid grid-rows-* grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-2">
|
<CusTabs :selected-color="tabColor">
|
||||||
<div class="rounded p-2 shadow">
|
<CusTab name="person" title="Oseba">
|
||||||
<p class="text-xs leading-5 md:text-sm text-gray-500">Nu.</p>
|
<div class="flex justify-end mb-2">
|
||||||
<p class="text-sm md:text-base leading-7 text-gray-900">{{ person.nu }}</p>
|
<span class=" border-b-2 border-gray-500 hover:border-gray-800">
|
||||||
</div>
|
<button @click="openDrawerUpdateClient"><UserEditIcon size="lg" css="text-gray-500 hover:text-gray-800" /></button>
|
||||||
<div class="rounded p-2 shadow">
|
</span>
|
||||||
<p class="text-sm leading-5 md:text-sm text-gray-500">Name.</p>
|
</div>
|
||||||
<p class="text-sm md:text-base leading-7 text-gray-900">{{ person.full_name }}</p>
|
<div class="grid grid-rows-* grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-2">
|
||||||
</div>
|
<div class="rounded p-2 shadow">
|
||||||
<div class="rounded p-2 shadow">
|
<p class="text-xs leading-5 md:text-sm text-gray-500">Nu.</p>
|
||||||
<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.nu }}</p>
|
||||||
<p class="text-sm md:text-base leading-7 text-gray-900">{{ person.tax_number }}</p>
|
</div>
|
||||||
</div>
|
<div class="rounded p-2 shadow">
|
||||||
<div class="rounded p-2 shadow">
|
<p class="text-sm leading-5 md:text-sm text-gray-500">Name.</p>
|
||||||
<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.full_name }}</p>
|
||||||
<p class="text-sm md:text-base leading-7 text-gray-900">{{ person.social_security_number }}</p>
|
</div>
|
||||||
</div>
|
<div class="rounded p-2 shadow">
|
||||||
|
<p class="text-sm leading-5 md:text-sm text-gray-500">Tax NU.</p>
|
||||||
</div>
|
<p class="text-sm md:text-base leading-7 text-gray-900">{{ person.tax_number }}</p>
|
||||||
<div class="grid grid-rows-* grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-2 mt-1">
|
</div>
|
||||||
<div class="rounded p-2 shadow">
|
<div class="rounded p-2 shadow">
|
||||||
<p class="text-sm leading-5 md:text-sm text-gray-500">Address</p>
|
<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.main_address }}</p>
|
<p class="text-sm md:text-base leading-7 text-gray-900">{{ person.social_security_number }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="rounded p-2 shadow">
|
</div>
|
||||||
<p class="text-sm leading-5 md:text-sm text-gray-500">Phone</p>
|
<div class="grid grid-rows-* grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-2 mt-1">
|
||||||
<p class="text-sm md:text-base leading-7 text-gray-900">{{ person.main_phone }}</p>
|
<div class="rounded p-2 shadow">
|
||||||
</div>
|
<p class="text-sm leading-5 md:text-sm text-gray-500">Address</p>
|
||||||
<div class="md:col-span-full lg:col-span-1 rounded p-2 shadow">
|
<p class="text-sm md:text-base leading-7 text-gray-900">{{ getMainAddress(person.addresses) }}</p>
|
||||||
<p class="text-sm leading-5 md:text-sm text-gray-500">Description</p>
|
</div>
|
||||||
<p class="text-sm md:text-base leading-7 text-gray-900">{{ person.description }}</p>
|
<div class="rounded p-2 shadow">
|
||||||
</div>
|
<p class="text-sm leading-5 md:text-sm text-gray-500">Phone</p>
|
||||||
</div>
|
<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>
|
</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>
|
<script setup>
|
||||||
import { computed, onMounted, ref, watch } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { Head, Link, router, usePage } from '@inertiajs/vue3';
|
import { Head, Link, router, usePage } from '@inertiajs/vue3';
|
||||||
import ApplicationMark from '@/Components/ApplicationMark.vue';
|
import ApplicationMark from '@/Components/ApplicationMark.vue';
|
||||||
import Banner from '@/Components/Banner.vue';
|
import Banner from '@/Components/Banner.vue';
|
||||||
|
|
@ -8,66 +8,19 @@ import DropdownLink from '@/Components/DropdownLink.vue';
|
||||||
import NavLink from '@/Components/NavLink.vue';
|
import NavLink from '@/Components/NavLink.vue';
|
||||||
import ResponsiveNavLink from '@/Components/ResponsiveNavLink.vue';
|
import ResponsiveNavLink from '@/Components/ResponsiveNavLink.vue';
|
||||||
import Breadcrumbs from '@/Components/Breadcrumbs.vue';
|
import Breadcrumbs from '@/Components/Breadcrumbs.vue';
|
||||||
import axios from 'axios';
|
import GlobalSearch from './Partials/GlobalSearch.vue';
|
||||||
import { debounce } from 'lodash';
|
|
||||||
import { FwbButton, FwbInput, FwbListGroup, FwbListGroupItem } from 'flowbite-vue';
|
|
||||||
import { AdjustmentIcon, SearchIcon } from '@/Utilities/Icons';
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
title: String,
|
title: String,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const showingNavigationDropdown = ref(false);
|
const showingNavigationDropdown = ref(false);
|
||||||
const querySearchDiv = ref(null);
|
|
||||||
|
|
||||||
const querySearch = ref('');
|
|
||||||
|
|
||||||
const querySearchList = ref(true);
|
|
||||||
const querySearchResult = ref([]);
|
|
||||||
|
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
router.post(route('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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -111,47 +64,14 @@ watch(querySearch, (value) => {
|
||||||
Nastavitve
|
Nastavitve
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="hidden space-x-8 sm:-my-px sm:items-center sm:ms-10 sm:flex">
|
||||||
|
<GlobalSearch />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="hidden sm:flex sm:items-center sm:ms-6">
|
<div class="hidden sm:flex sm:items-center sm:ms-6">
|
||||||
<!-- Settings Dropdown -->
|
<!-- 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">
|
<div class="ms-3 relative">
|
||||||
<Dropdown align="right" width="48">
|
<Dropdown align="right" width="48">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
|
|
@ -314,50 +234,13 @@ watch(querySearch, (value) => {
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<!-- Page Heading -->
|
<!-- Page Heading -->
|
||||||
<header v-if="$slots.header" class="bg-white shadow ">
|
<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">
|
<div class="max-w-7xl mx-auto py-4 px-4 sm:px-6 lg:px-8">
|
||||||
<Breadcrumbs :breadcrumbs="$page.props.breadcrumbs"></Breadcrumbs>
|
<Breadcrumbs :breadcrumbs="$page.props.breadcrumbs"></Breadcrumbs>
|
||||||
|
|
||||||
</div>
|
</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>
|
<script setup>
|
||||||
import PersonInfoGrid from '@/Components/PersonInfoGrid.vue';
|
import PersonInfoGrid from "@/Components/PersonInfoGrid.vue";
|
||||||
import SectionTitle from '@/Components/SectionTitle.vue';
|
import SectionTitle from "@/Components/SectionTitle.vue";
|
||||||
import AppLayout from '@/Layouts/AppLayout.vue';
|
import AppLayout from "@/Layouts/AppLayout.vue";
|
||||||
import { Link, useForm } from '@inertiajs/vue3';
|
import { FwbButton } from "flowbite-vue";
|
||||||
import { FwbA, FwbButton } from 'flowbite-vue';
|
import { onBeforeMount, ref } from "vue";
|
||||||
import { ref } from 'vue';
|
import ContractDrawer from "./Partials/ContractDrawer.vue";
|
||||||
import ContractDrawer from './Partials/ContractDrawer.vue';
|
import ContractTable from "./Partials/ContractTable.vue";
|
||||||
import ContractTable from './Partials/ContractTable.vue';
|
import ActivityDrawer from "./Partials/ActivityDrawer.vue";
|
||||||
import ActivityDrawer from './Partials/ActivityDrawer.vue';
|
import ActivityTable from "./Partials/ActivityTable.vue";
|
||||||
import ActivityTable from './Partials/ActivityTable.vue';
|
import { AngleDownIcon, AngleUpIcon } from "@/Utilities/Icons";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
client: Object,
|
client: Object,
|
||||||
client_case: Object,
|
client_case: Object,
|
||||||
contracts: Array,
|
contracts: Array,
|
||||||
activities: Object,
|
activities: Object,
|
||||||
contract_types: Array,
|
contract_types: Array,
|
||||||
actions: Array
|
actions: Array,
|
||||||
|
types: Object
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(props.actions);
|
const clientDetails = ref(true);
|
||||||
|
|
||||||
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
|
|
||||||
});
|
|
||||||
|
|
||||||
//Drawer add new contract
|
//Drawer add new contract
|
||||||
|
|
||||||
const drawerCreateContract = ref(false);
|
const drawerCreateContract = ref(false);
|
||||||
|
|
||||||
const openDrawerCreateContract = () => {
|
const openDrawerCreateContract = () => {
|
||||||
drawerCreateContract.value = true;
|
drawerCreateContract.value = true;
|
||||||
}
|
};
|
||||||
|
|
||||||
//Drawer add new activity
|
//Drawer add new activity
|
||||||
|
|
||||||
const drawerAddActivity = ref(false);
|
const drawerAddActivity = ref(false);
|
||||||
|
|
||||||
const openDrawerAddActivity = () => {
|
const openDrawerAddActivity = () => {
|
||||||
drawerAddActivity.value = true;
|
drawerAddActivity.value = true;
|
||||||
}
|
};
|
||||||
|
|
||||||
//Close drawer (all)
|
//Close drawer (all)
|
||||||
const closeDrawer = () => {
|
const closeDrawer = () => {
|
||||||
drawerCreateContract.value = false;
|
drawerCreateContract.value = false;
|
||||||
drawerAddActivity.value = false;
|
drawerAddActivity.value = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
const showClientDetails = () => {
|
||||||
|
clientDetails.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const hideClietnDetails = () => {
|
||||||
|
clientDetails.value = true;
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<AppLayout title="Client case">
|
<AppLayout title="Client case">
|
||||||
<template #header></template>
|
<template #header></template>
|
||||||
<div class="pt-12">
|
<div class="pt-12">
|
||||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
<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
|
||||||
<div class="mx-auto max-w-4x1 p-3">
|
class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4 border-blue-500"
|
||||||
<SectionTitle>
|
>
|
||||||
<template #title>
|
<div class="mx-auto max-w-4x1 p-3 flex justify-between">
|
||||||
<FwbA class= "hover:text-blue-500" :href="route('client.show', client)">
|
<SectionTitle>
|
||||||
{{ clientInfo.full_name }}
|
<template #title>
|
||||||
</FwbA>
|
<a class="hover:text-blue-500" :href="route('client.show', client)">
|
||||||
</template>
|
{{ client.person.full_name }}
|
||||||
|
</a>
|
||||||
</SectionTitle>
|
</template>
|
||||||
</div>
|
</SectionTitle>
|
||||||
</div>
|
<button @click="showClientDetails" :hidden="clientDetails ? false : true">
|
||||||
</div>
|
<AngleUpIcon />
|
||||||
|
</button>
|
||||||
|
<button :hidden="clientDetails" @click="hideClietnDetails">
|
||||||
|
<AngleDownIcon />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--div class="pt-1">
|
</div>
|
||||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
</div>
|
||||||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4 border-blue-400">
|
<div class="pt-1" :hidden="clientDetails">
|
||||||
<div class="mx-auto max-w-4x1 p-3">
|
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||||
<PersonInfoGrid :person="clientInfo" />
|
<div
|
||||||
</div>
|
class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4 border-blue-400"
|
||||||
</div>
|
>
|
||||||
</div>
|
<div class="mx-auto max-w-4x1 p-3">
|
||||||
</div-->
|
<PersonInfoGrid :types="types" :person="client.person" />
|
||||||
<div class="pt-6">
|
</div>
|
||||||
<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">
|
</div>
|
||||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
</div>
|
||||||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4 border-red-400">
|
<div class="pt-6">
|
||||||
<div class="mx-auto max-w-4x1 p-3">
|
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||||
<PersonInfoGrid :person="casePersonInfo" />
|
<div
|
||||||
</div>
|
class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4 border-red-400"
|
||||||
</div>
|
>
|
||||||
</div>
|
<div class="mx-auto max-w-4x1 p-3">
|
||||||
|
<SectionTitle>
|
||||||
|
<template #title> Primer - oseba </template>
|
||||||
|
</SectionTitle>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="pt-12">
|
</div>
|
||||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
</div>
|
||||||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4">
|
<div class="pt-1">
|
||||||
<div class="mx-auto max-w-4x1">
|
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||||
<div class="flex justify-between p-3">
|
<div
|
||||||
<SectionTitle>
|
class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4 border-red-400"
|
||||||
<template #title>
|
>
|
||||||
Pogodbe
|
<div class="mx-auto max-w-4x1 p-3">
|
||||||
</template>
|
<PersonInfoGrid :types="types" tab-color="red-600" :person="client_case.person" />
|
||||||
</SectionTitle>
|
</div>
|
||||||
<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-12 pb-6">
|
</div>
|
||||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
</div>
|
||||||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4">
|
<div class="pt-12">
|
||||||
<div class="mx-auto max-w-4x1">
|
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||||
<div class="flex justify-between p-3">
|
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4">
|
||||||
<SectionTitle>
|
<div class="mx-auto max-w-4x1">
|
||||||
<template #title>
|
<div class="flex justify-between p-3">
|
||||||
Aktivnosti
|
<SectionTitle>
|
||||||
</template>
|
<template #title> Pogodbe </template>
|
||||||
</SectionTitle>
|
</SectionTitle>
|
||||||
<FwbButton @click="openDrawerAddActivity">Nova</FwbButton>
|
<FwbButton @click="openDrawerCreateContract">Nova</FwbButton>
|
||||||
</div>
|
|
||||||
<ActivityTable
|
|
||||||
:client_case="client_case"
|
|
||||||
:activities="activities"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<ContractTable
|
||||||
|
:client_case="client_case"
|
||||||
|
:contracts="contracts"
|
||||||
|
:contract_types="contract_types"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</AppLayout>
|
</div>
|
||||||
<ContractDrawer
|
</div>
|
||||||
:show="drawerCreateContract"
|
<div class="pt-12 pb-6">
|
||||||
@close="closeDrawer"
|
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||||
:types="contract_types"
|
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4">
|
||||||
:client_case="client_case"
|
<div class="mx-auto max-w-4x1">
|
||||||
/>
|
<div class="flex justify-between p-3">
|
||||||
<ActivityDrawer
|
<SectionTitle>
|
||||||
:show="drawerAddActivity"
|
<template #title> Aktivnosti </template>
|
||||||
@close="closeDrawer"
|
</SectionTitle>
|
||||||
:client_case="client_case"
|
<FwbButton @click="openDrawerAddActivity">Nova</FwbButton>
|
||||||
:actions="actions"
|
</div>
|
||||||
/>
|
<ActivityTable :client_case="client_case" :activities="activities" />
|
||||||
</template>
|
</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 List from '@/Components/List.vue';
|
||||||
import ListItem from '@/Components/ListItem.vue';
|
import ListItem from '@/Components/ListItem.vue';
|
||||||
import PrimaryButton from '@/Components/PrimaryButton.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 { ref } from 'vue';
|
||||||
import { Link, useForm } from '@inertiajs/vue3';
|
import { Link } from '@inertiajs/vue3';
|
||||||
import ActionMessage from '@/Components/ActionMessage.vue';
|
|
||||||
import SectionTitle from '@/Components/SectionTitle.vue';
|
import SectionTitle from '@/Components/SectionTitle.vue';
|
||||||
import PersonInfoGrid from '@/Components/PersonInfoGrid.vue';
|
import PersonInfoGrid from '@/Components/PersonInfoGrid.vue';
|
||||||
import Pagination from '@/Components/Pagination.vue';
|
import Pagination from '@/Components/Pagination.vue';
|
||||||
import SearchInput from '@/Components/SearchInput.vue';
|
import SearchInput from '@/Components/SearchInput.vue';
|
||||||
|
import FormCreateCase from './Partials/FormCreateCase.vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
client: Object,
|
client: Object,
|
||||||
client_cases: Object,
|
client_cases: Object,
|
||||||
urlPrev: String,
|
urlPrev: String,
|
||||||
filters: Object
|
filters: Object,
|
||||||
});
|
types: 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
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const search = {
|
const search = {
|
||||||
|
|
@ -65,42 +33,6 @@ const openDrawerCreateCase = () => {
|
||||||
drawerCreateCase.value = true;
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -109,12 +41,11 @@ const storeCase = () => {
|
||||||
<div class="pt-12">
|
<div class="pt-12">
|
||||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
<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="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>
|
<SectionTitle>
|
||||||
<template #title>
|
<template #title>
|
||||||
{{ client.person.full_name }}
|
{{ client.person.full_name }}
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
</SectionTitle>
|
</SectionTitle>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -123,8 +54,8 @@ const storeCase = () => {
|
||||||
<div class="pt-1">
|
<div class="pt-1">
|
||||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
<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="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 px-2">
|
||||||
<PersonInfoGrid :person="clientInfo"></PersonInfoGrid>
|
<PersonInfoGrid :types="types" :person="client.person"></PersonInfoGrid>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -162,141 +93,9 @@ const storeCase = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</AppLayout>
|
</AppLayout>
|
||||||
<Drawer
|
<FormCreateCase
|
||||||
:show="drawerCreateCase"
|
:show="drawerCreateCase"
|
||||||
@close="drawerCreateCase = false">
|
@close="drawerCreateCase = false"
|
||||||
|
:client-uuid="client?.uuid"
|
||||||
<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>
|
</template>
|
||||||
|
|
@ -6,10 +6,12 @@ import { LinkOptions as C_LINK, TableColumn as C_TD, TableRow as C_TR} from '@/S
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
chart: Object,
|
chart: Object,
|
||||||
people: Array
|
people: Array,
|
||||||
|
terrain: Array
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(props.people)
|
|
||||||
|
console.log(props.terrain)
|
||||||
|
|
||||||
|
|
||||||
const tablePersonHeader = [
|
const tablePersonHeader = [
|
||||||
|
|
@ -18,14 +20,21 @@ const tablePersonHeader = [
|
||||||
C_TD.make('Skupina', 'header')
|
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) => {
|
const getRoute = (person) => {
|
||||||
if( person.client ){
|
if( person.client ){
|
||||||
return {route: 'client.show', options: 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) => {
|
props.people.forEach((p) => {
|
||||||
|
|
@ -34,12 +43,25 @@ props.people.forEach((p) => {
|
||||||
const cols = [
|
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(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.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}`}))
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -67,7 +89,7 @@ props.people.forEach((p) => {
|
||||||
Seznam primerov za terensko delo
|
Seznam primerov za terensko delo
|
||||||
</template>
|
</template>
|
||||||
</SectionTitle>
|
</SectionTitle>
|
||||||
<BasicTable :header="tablePersonHeader" :body="tablePersonBody"></BasicTable>
|
<BasicTable :header="tblTerrainHead" :body="tblTerrainBody"></BasicTable>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
|
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
|
||||||
<SectionTitle class="p-4">
|
<SectionTitle class="p-4">
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ const activeTab = ref('actions')
|
||||||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
|
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
|
||||||
<fwb-tabs v-model="activeTab" variant="underline" >
|
<fwb-tabs v-model="activeTab" variant="underline" >
|
||||||
<fwb-tab name="actions" title="Actions">
|
<fwb-tab name="actions" title="Actions">
|
||||||
<ActionTable :actions="actions" />
|
<ActionTable :actions="actions" :decisions="decisions" />
|
||||||
</fwb-tab>
|
</fwb-tab>
|
||||||
<fwb-tab name="decisions" title="Decisions">
|
<fwb-tab name="decisions" title="Decisions">
|
||||||
<DecisionTable :decisions="decisions" />
|
<DecisionTable :decisions="decisions" />
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,69 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { FwbTable, FwbTableBody, FwbTableHead, FwbTableHeadCell, FwbTableCell, FwbTableRow } from 'flowbite-vue';
|
import { FwbTable, FwbTableBody, FwbTableHead, FwbTableHeadCell, FwbTableCell, FwbTableRow } from 'flowbite-vue';
|
||||||
import { EditIcon, TrashBinIcon } from '@/Utilities/Icons';
|
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({
|
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>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -27,10 +84,63 @@ const props = defineProps({
|
||||||
<fwb-table-cell>{{ act.color_tag }}</fwb-table-cell>
|
<fwb-table-cell>{{ act.color_tag }}</fwb-table-cell>
|
||||||
<fwb-table-cell>{{ act.decisions.length }}</fwb-table-cell>
|
<fwb-table-cell>{{ act.decisions.length }}</fwb-table-cell>
|
||||||
<fwb-table-cell>
|
<fwb-table-cell>
|
||||||
<button><EditIcon /></button>
|
<button @click="openEditDrawer(act)"><EditIcon /></button>
|
||||||
<button><TrashBinIcon /></button>
|
|
||||||
</fwb-table-cell>
|
</fwb-table-cell>
|
||||||
</fwb-table-row>
|
</fwb-table-row>
|
||||||
</fwb-table-body>
|
</fwb-table-body>
|
||||||
</fwb-table>
|
</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>
|
</template>
|
||||||
|
|
@ -1,13 +1,37 @@
|
||||||
|
|
||||||
import { ref } from "vue";
|
|
||||||
|
|
||||||
const Icon = {
|
const Icon = {
|
||||||
props: {
|
props: {
|
||||||
css: {
|
css: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'text-gray-800'
|
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 = {
|
const AddressBookIcon = {
|
||||||
|
|
@ -15,52 +39,98 @@ const AddressBookIcon = {
|
||||||
setup: () => {
|
setup: () => {
|
||||||
console.log(this.props)
|
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"/>
|
<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>`
|
</svg>`
|
||||||
};
|
};
|
||||||
|
|
||||||
const AlignCenterIcon = {
|
const AlignCenterIcon = {
|
||||||
__proto__: Icon,
|
__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"/>
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 6h8M6 10h12M8 14h8M6 18h12"/>
|
||||||
</svg>`
|
</svg>`
|
||||||
}
|
}
|
||||||
|
|
||||||
const EditIcon = {
|
const EditIcon = {
|
||||||
__proto__: Icon,
|
__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"/>
|
<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>`
|
</svg>`
|
||||||
}
|
}
|
||||||
|
|
||||||
const TrashBinIcon = {
|
const TrashBinIcon = {
|
||||||
__proto__: Icon,
|
__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"/>
|
<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>`
|
</svg>`
|
||||||
}
|
}
|
||||||
|
|
||||||
const SearchIcon = {
|
const SearchIcon = {
|
||||||
__proto__: Icon,
|
__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" />
|
<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>`
|
</svg>`
|
||||||
}
|
}
|
||||||
|
|
||||||
const AdjustmentIcon = {
|
const AdjustmentIcon = {
|
||||||
__proto__: Icon,
|
__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"/>
|
<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>
|
</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 {
|
export {
|
||||||
AddressBookIcon,
|
AddressBookIcon,
|
||||||
AlignCenterIcon,
|
AlignCenterIcon,
|
||||||
EditIcon,
|
EditIcon,
|
||||||
TrashBinIcon,
|
TrashBinIcon,
|
||||||
SearchIcon,
|
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 { ZiggyVue } from '../../vendor/tightenco/ziggy';
|
||||||
import VueApexCharts from 'vue3-apexcharts';
|
import VueApexCharts from 'vue3-apexcharts';
|
||||||
import VueDatePicker from '@vuepic/vue-datepicker';
|
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';
|
const appName = import.meta.env.VITE_APP_NAME || 'Laravel';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use App\Charts\ExampleChart;
|
use App\Charts\ExampleChart;
|
||||||
|
use App\Http\Controllers\PersonController;
|
||||||
use App\Http\Controllers\ClientCaseContoller;
|
use App\Http\Controllers\ClientCaseContoller;
|
||||||
use App\Http\Controllers\ClientController;
|
use App\Http\Controllers\ClientController;
|
||||||
use App\Http\Controllers\ContractController;
|
use App\Http\Controllers\ContractController;
|
||||||
|
|
@ -21,7 +22,7 @@
|
||||||
])->group(function () {
|
])->group(function () {
|
||||||
Route::get('/dashboard', function () {
|
Route::get('/dashboard', function () {
|
||||||
$chart = new ExampleChart(new LarapexChart());
|
$chart = new ExampleChart(new LarapexChart());
|
||||||
$people = Person::with(['group','type', 'client', 'clientCase'])
|
$people = Person::with(['group', 'type', 'client', 'clientCase'])
|
||||||
->where([
|
->where([
|
||||||
['active','=',1],
|
['active','=',1],
|
||||||
])
|
])
|
||||||
|
|
@ -29,11 +30,21 @@
|
||||||
->orderByDesc('created_at')
|
->orderByDesc('created_at')
|
||||||
->get();
|
->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(
|
return Inertia::render(
|
||||||
'Dashboard',
|
'Dashboard',
|
||||||
[
|
[
|
||||||
'chart' => $chart->build(),
|
'chart' => $chart->build(),
|
||||||
'people' => $people
|
'people' => $people,
|
||||||
|
'terrain' => $terrain
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
})->name('dashboard');
|
})->name('dashboard');
|
||||||
|
|
@ -45,24 +56,6 @@
|
||||||
Route::get('search', function(Request $request) {
|
Route::get('search', function(Request $request) {
|
||||||
|
|
||||||
if( !empty($request->input('query')) ) {
|
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'))
|
$clients = App\Models\Person\Person::search($request->input('query'))
|
||||||
->query(function($builder) use($request): void {
|
->query(function($builder) use($request): void {
|
||||||
|
|
@ -95,10 +88,17 @@
|
||||||
return [];
|
return [];
|
||||||
})->name('search');
|
})->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
|
//client
|
||||||
Route::get('clients', [ClientController::class, 'index'])->name('client');
|
Route::get('clients', [ClientController::class, 'index'])->name('client');
|
||||||
Route::get('clients/{client:uuid}', [ClientController::class, 'show'])->name('client.show');
|
Route::get('clients/{client:uuid}', [ClientController::class, 'show'])->name('client.show');
|
||||||
Route::post('clients', [ClientController::class, 'store'])->name('client.store');
|
Route::post('clients', [ClientController::class, 'store'])->name('client.store');
|
||||||
|
Route::put('clients/{client:uuid}', [ClientController::class, 'update'])->name('client.update');
|
||||||
|
|
||||||
//client-case
|
//client-case
|
||||||
Route::get('client-cases', [ClientCaseContoller::class, 'index'])->name('clientCase');
|
Route::get('client-cases', [ClientCaseContoller::class, 'index'])->name('clientCase');
|
||||||
|
|
@ -113,4 +113,14 @@
|
||||||
|
|
||||||
Route::get('settings', [SettingController::class, 'index'])->name('settings');
|
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