Compare commits
50 Commits
08133d0b05
...
cv
Author | SHA1 | Date | |
---|---|---|---|
45fbdd2759
|
|||
7c2f888702
|
|||
2f112db339
|
|||
a08c6c9529
|
|||
2d1d51f777
|
|||
fcf422678c
|
|||
ffee3b257d
|
|||
957e90aff6
|
|||
252f5ee6b7
|
|||
2a2869e2c6
|
|||
6a033d108c
|
|||
620217e1d5
|
|||
a7e93681f3
|
|||
9d7da548e3
|
|||
2349008131
|
|||
908b1e4bec
|
|||
54db2e8e2b
|
|||
127ebe79ae
|
|||
010f8cf278
|
|||
a7ccb3100f
|
|||
753421a5a0
|
|||
7fd3be06ea
|
|||
1ccc934561
|
|||
f32f13604f
|
|||
8974721c9c
|
|||
d47c719d13
|
|||
af3aa905bd
|
|||
d0b3f9094c
|
|||
d943e81da4
|
|||
f5977c1b5d
|
|||
992326ebf0
|
|||
021dfc85f9
|
|||
93bbf2296d
|
|||
0c7d2c9f24
|
|||
a09a75b69e
|
|||
58003e5d18
|
|||
f500c8691f
|
|||
5b71fa9781
|
|||
7c58a0bc63
|
|||
e294dc07e0
|
|||
996b1b4faf
|
|||
99f0bafe93
|
|||
ac90d45519
|
|||
95ae8c562d
|
|||
65f0a49cdb
|
|||
5839ef2a54
|
|||
e049990606
|
|||
d35421a97e
|
|||
390c5b8087
|
|||
9518d6a811
|
@@ -14,3 +14,6 @@ DB_PASSWORD=password
|
|||||||
EXTERNAL_WEBSERVER_PORT=80
|
EXTERNAL_WEBSERVER_PORT=80
|
||||||
CURRENT_UID=1000
|
CURRENT_UID=1000
|
||||||
XDG_CONFIG_HOME=/tmp
|
XDG_CONFIG_HOME=/tmp
|
||||||
|
|
||||||
|
VITE_CV_APP_URL=https://cv.kamilcraft.com
|
||||||
|
VITE_PORT=3001
|
||||||
|
55
app/Console/Commands/CVInfo.php
Normal file
55
app/Console/Commands/CVInfo.php
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Models\CV;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
|
class CVInfo extends Command
|
||||||
|
{
|
||||||
|
protected $signature = 'cv:info {id}';
|
||||||
|
|
||||||
|
protected $description = 'Show info about CV';
|
||||||
|
|
||||||
|
|
||||||
|
public function handle(): int
|
||||||
|
{
|
||||||
|
if (! ($cv = CV::find($id = $this->argument('id')))) {
|
||||||
|
$this->error('CV not found!');
|
||||||
|
return Command::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->line('ID: '. $cv->id);
|
||||||
|
$this->line('Token: '. $cv->token);
|
||||||
|
$this->line('Company: '. $cv->recipient);
|
||||||
|
$this->line('Phone: '. $cv->formattedPhoneNumber .', '. $cv->PhoneNumber);
|
||||||
|
$this->line('Locations: '. implode(' / ', $cv->locations));
|
||||||
|
$this->line('Actual views: '. $cv->info()->select('id')->get()->count());
|
||||||
|
$this->line('Registered views: '. $cv->views);
|
||||||
|
$this->line('Mission: '. (is_null($mission = $cv->mission) ? 'default' : $mission));
|
||||||
|
$this->line('RODO: '. (is_null($rodo = $cv->rodo) ? 'default' : $rodo));
|
||||||
|
$this->line('');
|
||||||
|
|
||||||
|
$this->line('Showed list:');
|
||||||
|
$listCVInfo = [];
|
||||||
|
foreach (($cvInfoList = $cv->info()->orderByDesc('id')->get(['id', 'ip', 'created_at'])) as $cvInfo) {
|
||||||
|
$listCVInfo[] = [
|
||||||
|
'id' => $cvInfo->id,
|
||||||
|
'ip' => $cvInfo->ip,
|
||||||
|
'created' => $cvInfo->created_at->format('d-m-Y H:i:s'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($cvInfoList->count() === 0)
|
||||||
|
$this->warn('Empty!');
|
||||||
|
else
|
||||||
|
$this->table(
|
||||||
|
['Id', 'IP', 'Showed'],
|
||||||
|
$listCVInfo,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Command::SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
@@ -15,7 +15,10 @@ class CreateCV extends Command
|
|||||||
{recipient : Company}
|
{recipient : Company}
|
||||||
{email : E-mail address}
|
{email : E-mail address}
|
||||||
{phone : Phone number - with spaces}
|
{phone : Phone number - with spaces}
|
||||||
{location?* : List of locations}';
|
{location?* : List of locations}
|
||||||
|
{--mission= : Description of mission}
|
||||||
|
{--rodo= : Description of rodo}
|
||||||
|
{--position= : Set position value}';
|
||||||
|
|
||||||
protected $description = 'Create CV';
|
protected $description = 'Create CV';
|
||||||
|
|
||||||
@@ -25,16 +28,24 @@ class CreateCV extends Command
|
|||||||
$email = $this->argument('email');
|
$email = $this->argument('email');
|
||||||
$phone = $this->argument('phone');
|
$phone = $this->argument('phone');
|
||||||
$locations = $this->argument('location');
|
$locations = $this->argument('location');
|
||||||
|
$mission = $this->option('mission');
|
||||||
|
$rodo = $this->option('rodo');
|
||||||
|
$position = $this->option('position');
|
||||||
|
|
||||||
CV::query()
|
CV::query()
|
||||||
->create([
|
->create([
|
||||||
// 'slug' => Str::ra,
|
'token' => Str::random(50),
|
||||||
'recipient' => $recipient,
|
'recipient' => $recipient,
|
||||||
'email' => $email,
|
'email' => $email,
|
||||||
'phone-number' => $phone,
|
'phone_number' => $phone,
|
||||||
'locations' => $locations,
|
'locations' => $locations,
|
||||||
|
'mission' => $mission,
|
||||||
|
'rodo' => $rodo,
|
||||||
|
'position' => $position,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$this->info('Created!');
|
||||||
|
|
||||||
return CommandAlias::SUCCESS;
|
return CommandAlias::SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
44
app/Console/Commands/ListCV.php
Normal file
44
app/Console/Commands/ListCV.php
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Http\Resources\CVResource;
|
||||||
|
use App\Models\CV;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
|
class ListCV extends Command
|
||||||
|
{
|
||||||
|
protected $signature = 'cv:list';
|
||||||
|
|
||||||
|
protected $description = 'List of CV';
|
||||||
|
|
||||||
|
public function handle(): int
|
||||||
|
{
|
||||||
|
$cvList = CV::all();
|
||||||
|
$cvListCollection = [];
|
||||||
|
|
||||||
|
/** @var CV $cv */
|
||||||
|
foreach ($cvList as $cv) {
|
||||||
|
$cvResource = (new CVResource($cv))->setAsConsole()->toArray();
|
||||||
|
$cvListCollection[] = [
|
||||||
|
'id' => $cvResource['id'],
|
||||||
|
'token' => $cvResource['token'],
|
||||||
|
'email' => $cvResource['email'],
|
||||||
|
'recipient' => $cvResource['recipient'],
|
||||||
|
'locations' => implode(' / ', $cvResource['locations']),
|
||||||
|
'phone' => $cvResource['phone']['formattedPhoneNumber'],
|
||||||
|
'views' => $cvResource['views'] . '/' . $cvResource['registeredViews'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($cvListCollection) > 0)
|
||||||
|
$this->table(
|
||||||
|
['Id', 'Token', 'E-mail', 'Company', 'Locations', 'Phone', 'Views'],
|
||||||
|
$cvListCollection
|
||||||
|
);
|
||||||
|
|
||||||
|
return Command::SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
25
app/Console/Commands/RemoveIPFromList.php
Normal file
25
app/Console/Commands/RemoveIPFromList.php
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use App\Models\CVInfo;
|
||||||
|
|
||||||
|
class RemoveIPFromList extends Command
|
||||||
|
{
|
||||||
|
protected $signature = 'cv:rm-ip {ip : IP address on list.}';
|
||||||
|
|
||||||
|
protected $description = 'Remove IP address from show list.';
|
||||||
|
|
||||||
|
public function handle(): int
|
||||||
|
{
|
||||||
|
$ip = $this->argument('ip');
|
||||||
|
$cvInfo = CVInfo::query()->where('ip', $ip);
|
||||||
|
$cvInfo->delete();
|
||||||
|
$this->info('IP '. $ip .' deleted from database.');
|
||||||
|
|
||||||
|
return Command::SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
80
app/Console/Commands/UpdateCV.php
Normal file
80
app/Console/Commands/UpdateCV.php
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use App\Models\CV;
|
||||||
|
|
||||||
|
class UpdateCV extends Command
|
||||||
|
{
|
||||||
|
protected $signature = 'cv:update
|
||||||
|
{id : ID CV element}
|
||||||
|
{--company= : Company name}
|
||||||
|
{--phone= : Phone number}
|
||||||
|
{--begin-location : Add begin}
|
||||||
|
{--add-location=* : Add locations}
|
||||||
|
{--remove-location=* : Remove lcoations}
|
||||||
|
{--mission= : Set new text value}
|
||||||
|
{--rodo= : Set new text value}
|
||||||
|
{--position= : Set position value}';
|
||||||
|
|
||||||
|
protected $description = 'Update CV element';
|
||||||
|
|
||||||
|
public function handle(): int
|
||||||
|
{
|
||||||
|
if (! ($id = $this->argument('id')) || $id <= 0) {
|
||||||
|
$this->error('Incorrect id');
|
||||||
|
return Command::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cv = CV::find($id);
|
||||||
|
|
||||||
|
if ($company = $this->option('company')) {
|
||||||
|
$cv->recipient = $company;
|
||||||
|
}
|
||||||
|
if ($phone = $this->option('phone')) {
|
||||||
|
$cv->phone_number = $phone;
|
||||||
|
}
|
||||||
|
if (count($addLocations = $this->option('remove-location')) > 0) {
|
||||||
|
$locations = $cv->locations;
|
||||||
|
$locations = array_diff($locations, $addLocations);
|
||||||
|
$cv->locations = $locations;
|
||||||
|
}
|
||||||
|
if (count($addLocations = $this->option('add-location')) > 0) {
|
||||||
|
$locations = $cv->locations;
|
||||||
|
|
||||||
|
$clearLocations = [];
|
||||||
|
foreach ($addLocations as $location) {
|
||||||
|
if (in_array($location, $locations)) {
|
||||||
|
$this->warn('"'. $location .'" exists! This value was not added.');
|
||||||
|
$clearLocations[] = $location;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$addLocations = array_diff($addLocations, $clearLocations);
|
||||||
|
|
||||||
|
if ($this->option('begin-location'))
|
||||||
|
$locations = array_merge($addLocations, $locations);
|
||||||
|
else
|
||||||
|
$locations = array_merge($locations, $addLocations);
|
||||||
|
$cv->locations = $locations;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($mission = $this->option('mission')) {
|
||||||
|
$cv->mission = $mission === 'null' ? null : $mission;
|
||||||
|
}
|
||||||
|
if ($rodo = $this->option('rodo')) {
|
||||||
|
$cv->rodo = $rodo === 'null' ? null : $rodo;
|
||||||
|
}
|
||||||
|
if ($position = $this->option('position')) {
|
||||||
|
$cv->position = $position === 'null' ? null : $position;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cv->save();
|
||||||
|
|
||||||
|
$this->info('Updated!');
|
||||||
|
|
||||||
|
return Command::SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
24
app/Http/Controllers/Api/CVController.php
Normal file
24
app/Http/Controllers/Api/CVController.php
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Resources\CVResource;
|
||||||
|
use App\Models\CV;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
class CVController extends Controller
|
||||||
|
{
|
||||||
|
public function show(CV $cv): JsonResource
|
||||||
|
{
|
||||||
|
$cv->info()
|
||||||
|
->create([
|
||||||
|
'ip' => $_SERVER['REMOTE_ADDR'],
|
||||||
|
]);
|
||||||
|
$cv->update(['views' => $cv->views+=1]);
|
||||||
|
|
||||||
|
return new CVResource($cv);
|
||||||
|
}
|
||||||
|
}
|
27
app/Http/Controllers/Api/MessageController.php
Normal file
27
app/Http/Controllers/Api/MessageController.php
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\MessageRequest;
|
||||||
|
use App\Models\Message;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
|
class MessageController extends Controller
|
||||||
|
{
|
||||||
|
public function store(MessageRequest $request): JsonResponse
|
||||||
|
{
|
||||||
|
$data = $request->toArray();
|
||||||
|
Message::query()->create([
|
||||||
|
'message' => $data['message'],
|
||||||
|
'email' => $data['email'],
|
||||||
|
'sender' => $data['sender'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Dziękuję za wiadomość! Odpowiem możliwie najszybciej.'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@@ -8,8 +8,7 @@ use App\Http\Controllers\Controller;
|
|||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Hash;
|
use Inertia\Response as InertiaResponse;
|
||||||
use Illuminate\View\View;
|
|
||||||
|
|
||||||
class LoginController extends Controller
|
class LoginController extends Controller
|
||||||
{
|
{
|
||||||
@@ -43,12 +42,12 @@ class LoginController extends Controller
|
|||||||
return redirect()->route('admin.auth.login');
|
return redirect()->route('admin.auth.login');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function login(): View|RedirectResponse
|
public function login(): InertiaResponse|RedirectResponse
|
||||||
{
|
{
|
||||||
if (Auth::check())
|
if (Auth::check())
|
||||||
return redirect()->route('admin.home');
|
return redirect()->route('admin.home');
|
||||||
|
|
||||||
return view('auth.login');
|
return inertia('Login');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -6,7 +6,7 @@ use App\Http\Controllers\Controller;
|
|||||||
use App\Repository\Interfaces\CategoryRepository;
|
use App\Repository\Interfaces\CategoryRepository;
|
||||||
use App\Repository\Interfaces\ProjectRepository;
|
use App\Repository\Interfaces\ProjectRepository;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\View\View;
|
use Inertia\Response as InertiaResponse;
|
||||||
|
|
||||||
class AdminPanelController extends Controller
|
class AdminPanelController extends Controller
|
||||||
{
|
{
|
||||||
@@ -16,14 +16,15 @@ class AdminPanelController extends Controller
|
|||||||
private ProjectRepository $projectRepository
|
private ProjectRepository $projectRepository
|
||||||
) {
|
) {
|
||||||
$this->categoryRepository->auth = true;
|
$this->categoryRepository->auth = true;
|
||||||
|
$this->projectRepository->auth = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __invoke(Request $request): View
|
public function __invoke(Request $request): InertiaResponse
|
||||||
{
|
{
|
||||||
$categories = $this->categoryRepository->all();
|
$categories = $this->categoryRepository->all();
|
||||||
$projects = $this->projectRepository->all();
|
$projects = $this->projectRepository->all();
|
||||||
|
|
||||||
return view('dashboard.home', compact('categories', 'projects'));
|
return inertia('Dashboard/Index', compact('categories', 'projects'));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
122
app/Http/Controllers/Dashboard/CVController.php
Normal file
122
app/Http/Controllers/Dashboard/CVController.php
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Dashboard;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\CVRequest;
|
||||||
|
use App\Http\Resources\CVInfoCollection;
|
||||||
|
use App\Http\Resources\FullCVCollection;
|
||||||
|
use App\Http\Resources\FullCVResource;
|
||||||
|
use App\Models\CV;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Inertia\Response as InertiaResponse;
|
||||||
|
|
||||||
|
class CVController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request): InertiaResponse
|
||||||
|
{
|
||||||
|
return inertia('CV/Index', [
|
||||||
|
'cvs' => new FullCVCollection(CV::all()),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show(CV $cv): InertiaResponse
|
||||||
|
{
|
||||||
|
return inertia('CV/Show', [
|
||||||
|
'cv' => new FullCVResource($cv),
|
||||||
|
'cvInfo' => new CVInfoCollection($cv->info()->orderByDesc('id')->get()),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create(): InertiaResponse
|
||||||
|
{
|
||||||
|
return inertia('CV/Create');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(CVRequest $request): RedirectResponse
|
||||||
|
{
|
||||||
|
CV::query()
|
||||||
|
->create([
|
||||||
|
'token' => Str::random(50),
|
||||||
|
'recipient' => $request->get('recipient'),
|
||||||
|
'email' => $request->get('email'),
|
||||||
|
'phone_number' => $request->get('phone_number'),
|
||||||
|
'locations' => ($locations = $request->get('locations')) === [''] ? [] : $locations,
|
||||||
|
'mission' => ($mission = $request->get('mission')) === [''] ? [] : $mission,
|
||||||
|
'rodo' => ($rodo =$request->get('rodo')) === '' ? null : $rodo,
|
||||||
|
'position' => $request->get('position'),
|
||||||
|
'notes' => $request->get('notes'),
|
||||||
|
]);
|
||||||
|
return redirect()
|
||||||
|
->route('admin.cv.store')
|
||||||
|
->with('success', 'Utworzono nowe CV dla firmy ' . $request->get('recipient'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateSendStatus(CV $cv): RedirectResponse
|
||||||
|
{
|
||||||
|
$cv->update([
|
||||||
|
'sended' => true,
|
||||||
|
'sended_timestamp' => now()
|
||||||
|
]);
|
||||||
|
return redirect()
|
||||||
|
->route('admin.cv.show', ['cv' => $cv])
|
||||||
|
->with('success', 'Status wysłania ustawiono jako "wysłano".');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit(CV $cv): InertiaResponse
|
||||||
|
{
|
||||||
|
return inertia('CV/Edit', [
|
||||||
|
'cv' => new FullCVResource($cv),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(CVRequest $request, CV $cv): RedirectResponse
|
||||||
|
{
|
||||||
|
$toUpdate = [
|
||||||
|
'recipient' => $request->get('recipient'),
|
||||||
|
'email' => $request->get('email'),
|
||||||
|
'phone_number' => $request->get('phone_number'),
|
||||||
|
'locations' => ($locations = $request->get('locations')) === [''] ? [] : $locations,
|
||||||
|
'mission' => ($mission = $request->get('mission')) === [''] ? [] : $mission,
|
||||||
|
'rodo' => ($rodo =$request->get('rodo')) === '' ? null : $rodo,
|
||||||
|
'position' => $request->get('position'),
|
||||||
|
'notes' => $request->get('notes'),
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($cv->sended && ! $request->boolean('sended')) {
|
||||||
|
$toUpdate = array_merge($toUpdate, [
|
||||||
|
'sended' => false,
|
||||||
|
'sended_timestamp' => null,
|
||||||
|
]);
|
||||||
|
} else if (! $cv->sended && $request->boolean('sended')) {
|
||||||
|
$toUpdate = array_merge($toUpdate, [
|
||||||
|
'sended' => true,
|
||||||
|
'sended_timestamp' => now(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$cv->update($toUpdate);
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->with('success', 'Zaktualizowano CV dla firmy ' . $request->get('recipient'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(CV $cv): InertiaResponse
|
||||||
|
{
|
||||||
|
return inertia('CV/ConfirmDelete', compact('cv'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(CV $cv): RedirectResponse
|
||||||
|
{
|
||||||
|
$name = $cv->recipient;
|
||||||
|
$cv->delete();
|
||||||
|
|
||||||
|
return redirect()
|
||||||
|
->route('admin.cv.index')
|
||||||
|
->with('info', 'Usunięto CV dla firmy '. $name .'.');
|
||||||
|
}
|
||||||
|
}
|
@@ -9,6 +9,7 @@ use App\Models\Category;
|
|||||||
use App\Repository\Interfaces\CategoryRepository;
|
use App\Repository\Interfaces\CategoryRepository;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
use Inertia\Response as InertiaResponse;
|
||||||
|
|
||||||
class CategoryController
|
class CategoryController
|
||||||
{
|
{
|
||||||
@@ -21,35 +22,35 @@ class CategoryController
|
|||||||
{
|
{
|
||||||
$validate = $request->validated();
|
$validate = $request->validated();
|
||||||
if ($this->categoryRepository->update($category, $validate)) {
|
if ($this->categoryRepository->update($category, $validate)) {
|
||||||
return back()->with('message', 'Zaktualizowano kategorię!');
|
return back()
|
||||||
|
->with('success', 'Zaktualizowano kategorię!');
|
||||||
}
|
}
|
||||||
|
|
||||||
return back()->withError(['message_error', 'Wystąpił błąd podczas aktualizacji!']);
|
return back()
|
||||||
|
->with(['error', 'Wystąpił błąd podczas aktualizacji!']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function store(CategoryRequest $request)
|
public function store(CategoryRequest $request)
|
||||||
{
|
{
|
||||||
$validate = $request->validated();
|
$category = $this->categoryRepository->create($request->validated());
|
||||||
if ($category = $this->categoryRepository->create($validate)) {
|
return redirect()
|
||||||
return redirect()->route('admin.category.update', ['category' => $category])->with('message', 'Utworzono kategorię!');
|
->route('admin.category.update', compact('category'))
|
||||||
}
|
->with('message', 'Utworzono kategorię!');
|
||||||
|
|
||||||
return back()->withError(['message_error', 'Wystąpił błąd podczas tworzenia!']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create(): View
|
public function create(): InertiaResponse
|
||||||
{
|
{
|
||||||
return view('dashboard.categories.create');
|
return inertia('Categories/Create');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function edit(Category $category): View
|
public function edit(Category $category): InertiaResponse
|
||||||
{
|
{
|
||||||
return view('dashboard.categories.edit', compact('category'));
|
return inertia('Categories/Edit', compact('category'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(Category $category): View
|
public function delete(Category $category): InertiaResponse
|
||||||
{
|
{
|
||||||
return view('dashboard.categories.delete', compact('category'));
|
return inertia('Categories/ConfirmDelete', compact('category'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function destroy(Category $category): RedirectResponse
|
public function destroy(Category $category): RedirectResponse
|
||||||
@@ -57,7 +58,9 @@ class CategoryController
|
|||||||
$name = $category->name;
|
$name = $category->name;
|
||||||
$category->delete();
|
$category->delete();
|
||||||
|
|
||||||
return redirect()->route('admin.home')->with('message', 'Usunięto kategorię "'. $name .'"');
|
return redirect()
|
||||||
|
->route('admin.home')
|
||||||
|
->with('info', 'Usunięto kategorię "'. $name .'"');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
45
app/Http/Controllers/Dashboard/MessageController.php
Normal file
45
app/Http/Controllers/Dashboard/MessageController.php
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Dashboard;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Resources\MessageCollection;
|
||||||
|
use App\Http\Resources\MessageResource;
|
||||||
|
use App\Models\Message;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Inertia\Response as InertiaResponse;
|
||||||
|
|
||||||
|
class MessageController extends Controller
|
||||||
|
{
|
||||||
|
public function index() : InertiaResponse {
|
||||||
|
return inertia('Messages/Index', [
|
||||||
|
'messages' => new MessageCollection(Message::query()->orderByDesc('id')->get()),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show(Message $message) : InertiaResponse
|
||||||
|
{
|
||||||
|
return inertia('Messages/Show', [
|
||||||
|
'message' => new MessageResource($message),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(Message $message) : InertiaResponse
|
||||||
|
{
|
||||||
|
return inertia('Messages/ConfirmDelete', [
|
||||||
|
'message' => new MessageResource($message),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(Message $message) : RedirectResponse
|
||||||
|
{
|
||||||
|
$sender = $message->sender;
|
||||||
|
$message->delete();
|
||||||
|
|
||||||
|
return redirect()
|
||||||
|
->route('admin.message.index')
|
||||||
|
->with('info', 'Wiadomość od '. $sender .' została usunięta.');
|
||||||
|
}
|
||||||
|
}
|
84
app/Http/Controllers/Dashboard/NoteController.php
Normal file
84
app/Http/Controllers/Dashboard/NoteController.php
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Dashboard;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\NoteRequest;
|
||||||
|
use App\Http\Resources\NoteCollection;
|
||||||
|
use App\Http\Resources\NoteResource;
|
||||||
|
use App\Models\Note;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Inertia\Response as InertiaResponse;
|
||||||
|
|
||||||
|
class NoteController extends Controller
|
||||||
|
{
|
||||||
|
public function index(): InertiaResponse
|
||||||
|
{
|
||||||
|
return inertia(
|
||||||
|
'Notes/Index',
|
||||||
|
[
|
||||||
|
'notes' => new NoteCollection(
|
||||||
|
Note::query()
|
||||||
|
->orderByDesc('id')
|
||||||
|
->get()
|
||||||
|
),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create(): InertiaResponse
|
||||||
|
{
|
||||||
|
return inertia('Notes/Create');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(NoteRequest $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$note = Note::query()->create([
|
||||||
|
'title' => $request->get('title'),
|
||||||
|
'note' => $request->get('note'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return redirect()
|
||||||
|
->route('admin.note.show', compact('note'))
|
||||||
|
->with('success', 'Utworzono nową notatkę.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show(Note $note): InertiaResponse
|
||||||
|
{
|
||||||
|
return inertia('Notes/Show', ['note' => new NoteResource($note)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit(Note $note): InertiaResponse
|
||||||
|
{
|
||||||
|
return inertia('Notes/Edit', ['note' => new NoteResource($note)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(NoteRequest $request, Note $note): RedirectResponse
|
||||||
|
{
|
||||||
|
$note->update([
|
||||||
|
'title' => $request->get('title'),
|
||||||
|
'note' => $request->get('note'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return redirect()
|
||||||
|
->route('admin.note.show', compact('note'))
|
||||||
|
->with('success', 'Notatka ' . $request->get('title') . ' została zaktualizowana.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(Note $note): InertiaResponse
|
||||||
|
{
|
||||||
|
return inertia('Notes/ConfirmDelete', ['note' => new NoteResource($note)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(Note $note): RedirectResponse
|
||||||
|
{
|
||||||
|
$title = $note->title;
|
||||||
|
$note->delete();
|
||||||
|
|
||||||
|
return redirect()
|
||||||
|
->route('admin.note.index')
|
||||||
|
->with('info', 'Notatka ' . $title . ' została usunięta.');
|
||||||
|
}
|
||||||
|
}
|
@@ -1,13 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Http\Controllers\Dashboard;
|
namespace App\Http\Controllers\Dashboard;
|
||||||
|
|
||||||
use App\Http\Requests\ProjectRequest;
|
use App\Http\Requests\ProjectRequest;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Repository\Interfaces\ProjectRepository;
|
use App\Repository\Interfaces\ProjectRepository;
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\View\View;
|
use Inertia\Response as InertiaResponse;
|
||||||
|
|
||||||
class ProjectController
|
class ProjectController
|
||||||
{
|
{
|
||||||
@@ -18,24 +19,25 @@ class ProjectController
|
|||||||
$this->projectRepository->auth = true;
|
$this->projectRepository->auth = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function edit(Project $project): View
|
public function edit(Project $project): InertiaResponse
|
||||||
{
|
{
|
||||||
return view('dashboard.projects.edit', compact('project'));
|
return inertia('Projects/Edit', compact('project'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(ProjectRequest $request, Project $project): RedirectResponse
|
public function update(ProjectRequest $request, Project $project): RedirectResponse
|
||||||
{
|
{
|
||||||
$validated = $request->validated();
|
if ($this->projectRepository->update($project, $request->validated())) {
|
||||||
if ($this->projectRepository->update($project, $validated)) {
|
return back()
|
||||||
return back()->with('message', 'Zaktualizowano projekt!');
|
->with('success', 'Zaktualizowano projekt!');
|
||||||
}
|
}
|
||||||
|
|
||||||
return back()->withError(['message_error', 'Wystąpił błąd podczas aktualizacji!']);
|
return back()
|
||||||
|
->with(['error', 'Wystąpił błąd podczas aktualizacji!']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create(): View
|
public function create(): InertiaResponse
|
||||||
{
|
{
|
||||||
return view('dashboard.projects.create');
|
return inertia('Projects/Create');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function store(ProjectRequest $request): RedirectResponse
|
public function store(ProjectRequest $request): RedirectResponse
|
||||||
@@ -44,22 +46,24 @@ class ProjectController
|
|||||||
if ($project = $this->projectRepository->create($validated)) {
|
if ($project = $this->projectRepository->create($validated)) {
|
||||||
return redirect()
|
return redirect()
|
||||||
->route('admin.project.update', compact('project'))
|
->route('admin.project.update', compact('project'))
|
||||||
->with('message', 'Utworzono projekt!');
|
->with('success', 'Utworzono projekt!');
|
||||||
}
|
}
|
||||||
|
|
||||||
return back()->withError(['message_error', 'Wystąpił błąd podczas tworzenia!']);
|
return back()->withError(['error', 'Wystąpił błąd podczas tworzenia!']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(Project $project): View
|
public function delete(Project $project): InertiaResponse
|
||||||
{
|
{
|
||||||
return view('dashboard.projects.delete', compact('project'));
|
return inertia('Projects/ConfirmDelete', compact('project'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function destroy(Project $project): RedirectResponse
|
public function destroy(Project $project): RedirectResponse
|
||||||
{
|
{
|
||||||
$title = $project->title;
|
$title = $project->title;
|
||||||
$project->delete();
|
$project->delete();
|
||||||
return redirect()->route('admin.home')->with('message', 'Usunięto projekt "'. $title .'"');
|
return redirect()
|
||||||
|
->route('admin.home')
|
||||||
|
->with('info', 'Usunięto projekt "'. $title .'"');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,7 @@ class Kernel extends HttpKernel
|
|||||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||||
\App\Http\Middleware\TrimStrings::class,
|
\App\Http\Middleware\TrimStrings::class,
|
||||||
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
||||||
Core::class
|
Core::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $middlewareGroups = [
|
protected $middlewareGroups = [
|
||||||
@@ -28,6 +28,7 @@ class Kernel extends HttpKernel
|
|||||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||||
\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class,
|
\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class,
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
|
\App\Http\Middleware\HandleInertiaRequests::class,
|
||||||
],
|
],
|
||||||
|
|
||||||
'api' => [
|
'api' => [
|
||||||
|
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Middleware;
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Inertia\Middleware;
|
use Inertia\Middleware;
|
||||||
|
|
||||||
@@ -12,7 +13,16 @@ class HandleInertiaRequests extends Middleware
|
|||||||
public function share(Request $request): array
|
public function share(Request $request): array
|
||||||
{
|
{
|
||||||
return array_merge(parent::share($request), [
|
return array_merge(parent::share($request), [
|
||||||
//
|
'responseMessages' => $this->getFlashData($request),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getFlashData(Request $request): Closure
|
||||||
|
{
|
||||||
|
return fn(): array => [
|
||||||
|
'success' => $request->session()->get('success'),
|
||||||
|
'error' => $request->session()->get('error'),
|
||||||
|
'info' => $request->session()->get('info'),
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Http\Middleware;
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
use Illuminate\Http\Middleware\TrustProxies as Middleware;
|
use Illuminate\Http\Middleware\TrustProxies as Middleware;
|
||||||
|
37
app/Http/Requests/CVRequest.php
Normal file
37
app/Http/Requests/CVRequest.php
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class CVRequest extends FormRequest
|
||||||
|
{
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'recipient' => 'required|string',
|
||||||
|
'email' => 'required|email',
|
||||||
|
'phone_number' => 'required|regex:/^([0-9\s\+]*)$/i|min:12|max:15',
|
||||||
|
'locations' => 'required|array',
|
||||||
|
'mission' => 'nullable|string',
|
||||||
|
'rodo' => 'nullable|string',
|
||||||
|
'position' => 'nullable|string',
|
||||||
|
'notes' => 'nullable|string',
|
||||||
|
'sended' => 'nullable|boolean',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function prepareForValidation(): void
|
||||||
|
{
|
||||||
|
$this->merge([
|
||||||
|
'sended' => $this->toBoolean($this->sended),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function toBoolean($booleable): bool
|
||||||
|
{
|
||||||
|
return filter_var($booleable, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
@@ -1,34 +1,34 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Http\Requests;
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
class CategoryRequest extends FormRequest
|
class CategoryRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
public function rules(): array
|
||||||
* Determine if the user is authorized to make this request.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function authorize()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the validation rules that apply to the request.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function rules()
|
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'name' => 'required|string|min:3|max:25',
|
'name' => 'required|string|min:3|max:25',
|
||||||
'slug' => 'required|string|min:3|max:25',
|
'slug' => 'required|string|min:3|max:25',
|
||||||
'priority' => 'required|numeric|min:0|max:10',
|
'priority' => 'required|numeric|min:0|max:10',
|
||||||
'default' => 'nullable|in:yes,1,true,on',
|
'default' => 'nullable|boolean',
|
||||||
'visible' => 'nullable|in:yes,1,true,on'
|
'visible' => 'required|boolean',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function prepareForValidation(): void
|
||||||
|
{
|
||||||
|
$this->merge([
|
||||||
|
'default' => $this->toBoolean($this->default),
|
||||||
|
'visible' => $this->toBoolean($this->visible),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function toBoolean($booleable): bool
|
||||||
|
{
|
||||||
|
return filter_var($booleable, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
34
app/Http/Requests/MessageRequest.php
Normal file
34
app/Http/Requests/MessageRequest.php
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class MessageRequest extends FormRequest
|
||||||
|
{
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'message' => 'required|string|min:3|max:500',
|
||||||
|
'sender' => 'required|string|min:3|max:50',
|
||||||
|
'email' => 'required|email|max:250',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function messages(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'message.required' => 'Pole wiadomości jest wymagane.',
|
||||||
|
'sender.required' => 'Pole nadawcy jest wymagane.',
|
||||||
|
'email.required' => 'Pole e-mail jest wymagane.',
|
||||||
|
'message.min' => 'Pole wiadomości wymaga 3 znaki.',
|
||||||
|
'sender.min' => 'Pole nadawcy wymaga 3 znaki.',
|
||||||
|
'message.max' => 'Pole wiadomości może mieć maksymalnie 50 znaków.',
|
||||||
|
'sender.max' => 'Pole nadawcy może mieć maksymalnie 500 znaków.',
|
||||||
|
'email.email' => 'Pole musi być e-mailem.',
|
||||||
|
'email.max' => 'Pole e-mail może mieć maksymalnie 250 znaków.',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
18
app/Http/Requests/NoteRequest.php
Normal file
18
app/Http/Requests/NoteRequest.php
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class NoteRequest extends FormRequest
|
||||||
|
{
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'title' => 'required|string|min:3|max:250',
|
||||||
|
'note' => 'required|string|min:3|max:1000',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@@ -1,27 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Http\Requests;
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
class ProjectRequest extends FormRequest
|
class ProjectRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
public function rules(): array
|
||||||
* Determine if the user is authorized to make this request.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function authorize()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the validation rules that apply to the request.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function rules()
|
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'title' => 'required|string|min:3|max:255',
|
'title' => 'required|string|min:3|max:255',
|
||||||
@@ -36,8 +23,20 @@ class ProjectRequest extends FormRequest
|
|||||||
|
|
||||||
'project_url' => 'nullable|string',
|
'project_url' => 'nullable|string',
|
||||||
'project_version' => 'nullable|string',
|
'project_version' => 'nullable|string',
|
||||||
'description' => 'nullable|string',
|
'description' => 'required|string|min:3',
|
||||||
'visible' => 'nullable|in:yes,1,true,on'
|
'visible' => 'required|boolean'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function prepareForValidation(): void
|
||||||
|
{
|
||||||
|
$this->merge([
|
||||||
|
'visible' => $this->toBoolean($this->visible),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function toBoolean($booleable): bool
|
||||||
|
{
|
||||||
|
return filter_var($booleable, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
17
app/Http/Resources/CVCollection.php
Normal file
17
app/Http/Resources/CVCollection.php
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||||
|
|
||||||
|
class CVCollection extends ResourceCollection
|
||||||
|
{
|
||||||
|
public function toArray($request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'data' => $this->collection,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
17
app/Http/Resources/CVInfoCollection.php
Normal file
17
app/Http/Resources/CVInfoCollection.php
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||||
|
|
||||||
|
class CVInfoCollection extends ResourceCollection
|
||||||
|
{
|
||||||
|
public function toArray($request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'data' => $this->collection,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
21
app/Http/Resources/CVInfoResource.php
Normal file
21
app/Http/Resources/CVInfoResource.php
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
class CVInfoResource extends JsonResource
|
||||||
|
{
|
||||||
|
public static $wrap = null;
|
||||||
|
|
||||||
|
public function toArray($request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
|
'ip' => $this->ip,
|
||||||
|
'created_at' => $this->created_at->format('d-m-Y H:i:s'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
50
app/Http/Resources/CVResource.php
Normal file
50
app/Http/Resources/CVResource.php
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
class CVResource extends JsonResource
|
||||||
|
{
|
||||||
|
public static $wrap = null;
|
||||||
|
|
||||||
|
private bool $isConsole = false;
|
||||||
|
|
||||||
|
public function toArray($request = null): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->when($this->isConsole, fn (): int => $this->id),
|
||||||
|
'token' => $this->token,
|
||||||
|
'email' => $this->email,
|
||||||
|
'recipient' => $this->when($this->isConsole, fn (): string => $this->recipient),
|
||||||
|
'phone' => new PhoneResource($this->resource),
|
||||||
|
'locations' => $this->locations,
|
||||||
|
'views' => $this->when(
|
||||||
|
$this->isConsole,
|
||||||
|
fn (): int => $this->resource->info()->select('id')->get()->count()
|
||||||
|
),
|
||||||
|
'registeredViews' => $this->when($this->isConsole, fn (): int => $this->views),
|
||||||
|
'mission' => $this->when(
|
||||||
|
!is_null($this->mission),
|
||||||
|
fn (): array => explode(PHP_EOL, $this->mission, 5)
|
||||||
|
),
|
||||||
|
'rodo' => $this->when(
|
||||||
|
!is_null($this->rodo),
|
||||||
|
$this->rodo
|
||||||
|
),
|
||||||
|
'position' => $this->when(
|
||||||
|
!is_null($this->position),
|
||||||
|
$this->position
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAsConsole(): self
|
||||||
|
{
|
||||||
|
$this->isConsole = true;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,17 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Http\Resources;
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
use Illuminate\Http\Resources\Json\ResourceCollection;
|
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||||
|
|
||||||
class CategoryCollection extends ResourceCollection
|
class CategoryCollection extends ResourceCollection
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Transform the resource collection into an array.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
|
||||||
*/
|
|
||||||
public function toArray($request)
|
public function toArray($request)
|
||||||
{
|
{
|
||||||
return CategoryResource::collection($this->collection);
|
return CategoryResource::collection($this->collection);
|
||||||
|
@@ -1,21 +1,16 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Http\Resources;
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
use Illuminate\Http\Resources\Json\JsonResource;
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
class CategoryResource extends JsonResource
|
class CategoryResource extends JsonResource
|
||||||
{
|
{
|
||||||
|
|
||||||
public static $wrap = null;
|
public static $wrap = null;
|
||||||
|
|
||||||
/**
|
public function toArray($request): array
|
||||||
* Transform the resource into an array.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
|
||||||
*/
|
|
||||||
public function toArray($request)
|
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'id' => $this->id,
|
'id' => $this->id,
|
||||||
|
16
app/Http/Resources/FullCVCollection.php
Normal file
16
app/Http/Resources/FullCVCollection.php
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||||
|
|
||||||
|
class FullCVCollection extends ResourceCollection
|
||||||
|
{
|
||||||
|
public function toArray($request): array|JsonResource
|
||||||
|
{
|
||||||
|
return FullCVResource::collection($this->collection);
|
||||||
|
}
|
||||||
|
}
|
36
app/Http/Resources/FullCVResource.php
Normal file
36
app/Http/Resources/FullCVResource.php
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
class FullCVResource extends JsonResource
|
||||||
|
{
|
||||||
|
public static $wrap = null;
|
||||||
|
|
||||||
|
public function toArray($request = null): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
|
'token' => $this->token,
|
||||||
|
'email' => $this->email,
|
||||||
|
'recipient' => $this->recipient,
|
||||||
|
'phone' => new PhoneResource($this->resource),
|
||||||
|
'locations' => $this->locations,
|
||||||
|
'views' => $this->resource->info()->select('id')->get()->count(),
|
||||||
|
'registeredViews' => $this->views,
|
||||||
|
'sended' => [
|
||||||
|
'status' => $this->sended,
|
||||||
|
'datetime' => $this->sended_timestamp?->format('d-m-Y H:i:s'),
|
||||||
|
],
|
||||||
|
'position' => $this->position,
|
||||||
|
'mission' => explode(PHP_EOL, $this->mission ?? '', 5),
|
||||||
|
'rodo' => $this->rodo,
|
||||||
|
'notes' => $this->notes,
|
||||||
|
'created' => $this->created_at->format('d-m-Y H:i:s'),
|
||||||
|
'updated' => $this->updated_at->format('d-m-Y H:i:s'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
17
app/Http/Resources/MessageCollection.php
Normal file
17
app/Http/Resources/MessageCollection.php
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||||
|
|
||||||
|
class MessageCollection extends ResourceCollection
|
||||||
|
{
|
||||||
|
public function toArray($request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'data' => $this->collection,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
22
app/Http/Resources/MessageResource.php
Normal file
22
app/Http/Resources/MessageResource.php
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
class MessageResource extends JsonResource
|
||||||
|
{
|
||||||
|
public static $wrap = null;
|
||||||
|
|
||||||
|
public function toArray($request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
|
'sender' => $this->sender,
|
||||||
|
'email' => $this->email,
|
||||||
|
'message' => $this->message,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
17
app/Http/Resources/NoteCollection.php
Normal file
17
app/Http/Resources/NoteCollection.php
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||||
|
|
||||||
|
class NoteCollection extends ResourceCollection
|
||||||
|
{
|
||||||
|
public function toArray($request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'data' => $this->collection,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
25
app/Http/Resources/NoteResource.php
Normal file
25
app/Http/Resources/NoteResource.php
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use App\Models\Note;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property Note $resource
|
||||||
|
*/
|
||||||
|
class NoteResource extends JsonResource
|
||||||
|
{
|
||||||
|
public static $wrap = null;
|
||||||
|
|
||||||
|
public function toArray($request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->resource->id,
|
||||||
|
'title' => $this->resource->title,
|
||||||
|
'note' => $this->resource->note,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
20
app/Http/Resources/PhoneResource.php
Normal file
20
app/Http/Resources/PhoneResource.php
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
class PhoneResource extends JsonResource
|
||||||
|
{
|
||||||
|
public static $wrap = null;
|
||||||
|
|
||||||
|
public function toArray($request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'number' => $this->phone_number,
|
||||||
|
'formattedNumber' => $this->formattedPhoneNumber,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@@ -1,18 +1,15 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Http\Resources;
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
use Illuminate\Http\Resources\Json\ResourceCollection;
|
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||||
|
|
||||||
class ProjectCollection extends ResourceCollection
|
class ProjectCollection extends ResourceCollection
|
||||||
{
|
{
|
||||||
/**
|
public function toArray($request): JsonResource
|
||||||
* Transform the resource collection into an array.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
|
||||||
*/
|
|
||||||
public function toArray($request)
|
|
||||||
{
|
{
|
||||||
return ProjectResource::collection($this->collection);
|
return ProjectResource::collection($this->collection);
|
||||||
}
|
}
|
||||||
|
@@ -1,21 +1,16 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Http\Resources;
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
use Illuminate\Http\Resources\Json\JsonResource;
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
class ProjectResource extends JsonResource
|
class ProjectResource extends JsonResource
|
||||||
{
|
{
|
||||||
|
|
||||||
public static $wrap = null;
|
public static $wrap = null;
|
||||||
|
|
||||||
/**
|
public function toArray($request): array
|
||||||
* Transform the resource into an array.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
|
||||||
*/
|
|
||||||
public function toArray($request)
|
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'id' => $this->id,
|
'id' => $this->id,
|
||||||
@@ -30,5 +25,4 @@ class ProjectResource extends JsonResource
|
|||||||
'description' => $this->description,
|
'description' => $this->description,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -4,16 +4,24 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
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\HasMany;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property int $id
|
* @property int $id
|
||||||
|
* @property string $token
|
||||||
* @property string $recipient
|
* @property string $recipient
|
||||||
* @property string $email
|
* @property string $email
|
||||||
* @property string $phoneNumber
|
* @property string|null $phoneNumber
|
||||||
* @property array $locations
|
* @property array $locations
|
||||||
|
* @property string|null $mission
|
||||||
|
* @property string|null $rodo
|
||||||
|
* @property string|null $position
|
||||||
|
* @property string|null $notes
|
||||||
* @property int $views
|
* @property int $views
|
||||||
|
* @property bool $sended
|
||||||
*/
|
*/
|
||||||
class CV extends Model
|
class CV extends Model
|
||||||
{
|
{
|
||||||
@@ -24,5 +32,38 @@ class CV extends Model
|
|||||||
protected $casts = [
|
protected $casts = [
|
||||||
'locations' => 'array',
|
'locations' => 'array',
|
||||||
'views' => 'integer',
|
'views' => 'integer',
|
||||||
|
'sended' => 'boolean',
|
||||||
|
'sended_timestamp' => 'datetime',
|
||||||
];
|
];
|
||||||
}
|
|
||||||
|
protected function phoneNumber(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn (mixed $value): string => str_replace(' ', '', $value ?? ''),
|
||||||
|
set: fn (mixed $value): string => str_replace(' ', '', $value ?? ''),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedPhoneNumber(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: function (mixed $value, array $attributes): ?string {
|
||||||
|
$number = str_replace(' ', '', $attributes['phone_number'] ?? '');
|
||||||
|
for ($i = 3; $i < 12; $i+=4) {
|
||||||
|
$number = substr_replace($number, ' ', $i, 0);
|
||||||
|
}
|
||||||
|
return $number;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function info(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(CVInfo::class, 'cv_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRouteKeyName(): string
|
||||||
|
{
|
||||||
|
return 'token';
|
||||||
|
}
|
||||||
|
}
|
28
app/Models/CVInfo.php
Normal file
28
app/Models/CVInfo.php
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property int $cv_id
|
||||||
|
* @property int $ip
|
||||||
|
*/
|
||||||
|
class CVInfo extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $table = 'cv_infos';
|
||||||
|
|
||||||
|
protected $guarded = [];
|
||||||
|
|
||||||
|
public function cv(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(CV::class, ownerKey: 'cv_id');
|
||||||
|
}
|
||||||
|
}
|
23
app/Models/Message.php
Normal file
23
app/Models/Message.php
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property string $message
|
||||||
|
* @property string $email
|
||||||
|
* @property string $sender
|
||||||
|
*/
|
||||||
|
class Message extends Model
|
||||||
|
{
|
||||||
|
use HasFactory,
|
||||||
|
SoftDeletes;
|
||||||
|
|
||||||
|
protected $guarded = [];
|
||||||
|
}
|
20
app/Models/Note.php
Normal file
20
app/Models/Note.php
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property string $title
|
||||||
|
* @property string $note
|
||||||
|
*/
|
||||||
|
class Note extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $guarded = [];
|
||||||
|
}
|
@@ -48,7 +48,7 @@ class CategoryRepository implements CategoryRepositoryInterface
|
|||||||
public function update(Category $category, array $data = []): bool
|
public function update(Category $category, array $data = []): bool
|
||||||
{
|
{
|
||||||
$data = $this->parseToArray($data);
|
$data = $this->parseToArray($data);
|
||||||
if (!$category->default && isset($data['default']) && $data['default'] === true)
|
if (!$category->default && $data['default'] === true)
|
||||||
$this->unsetDefault();
|
$this->unsetDefault();
|
||||||
|
|
||||||
return $category
|
return $category
|
||||||
@@ -58,7 +58,7 @@ class CategoryRepository implements CategoryRepositoryInterface
|
|||||||
public function create(array $data = []): Category
|
public function create(array $data = []): Category
|
||||||
{
|
{
|
||||||
$data = $this->parseToArray($data);
|
$data = $this->parseToArray($data);
|
||||||
if (isset($data['default']) && $data['default'] === true)
|
if ($data['default'] === true)
|
||||||
$this->unsetDefault();
|
$this->unsetDefault();
|
||||||
|
|
||||||
return $this->category
|
return $this->category
|
||||||
@@ -85,18 +85,12 @@ class CategoryRepository implements CategoryRepositoryInterface
|
|||||||
if (isset($data['priority']) && !is_integer($data['priority']))
|
if (isset($data['priority']) && !is_integer($data['priority']))
|
||||||
$toSave['priority'] = (int)$data['priority'];
|
$toSave['priority'] = (int)$data['priority'];
|
||||||
|
|
||||||
if (
|
$toSave['default'] = $data['default'];
|
||||||
isset($data['default']) &&
|
|
||||||
in_array($data['default'], ['yes', 'on', 1, true])
|
|
||||||
) $toSave['default'] = true;
|
|
||||||
else $toSave['default'] = false;
|
|
||||||
|
|
||||||
if (
|
if ($toSave['default'] === true)
|
||||||
(isset($toSave['default']) && $toSave['default'] === true) ||
|
$toSave['visible'] = true;
|
||||||
(isset($data['visible']) &&
|
else
|
||||||
in_array($data['visible'], ['yes', 'on', 1, true]))
|
$toSave['visible'] = $data['visible'];
|
||||||
) $toSave['visible'] = true;
|
|
||||||
else $toSave['visible'] = false;
|
|
||||||
|
|
||||||
return $toSave;
|
return $toSave;
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,6 @@ use App\Http\Resources\ProjectCollection;
|
|||||||
use App\Http\Resources\ProjectResource;
|
use App\Http\Resources\ProjectResource;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Repository\Interfaces\ProjectRepository as ProjectRepositoryInterface;
|
use App\Repository\Interfaces\ProjectRepository as ProjectRepositoryInterface;
|
||||||
use Illuminate\Database\Query\Builder;
|
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
class ProjectRepository implements ProjectRepositoryInterface
|
class ProjectRepository implements ProjectRepositoryInterface
|
||||||
@@ -104,11 +103,7 @@ class ProjectRepository implements ProjectRepositoryInterface
|
|||||||
else
|
else
|
||||||
$toSave['update_date'] = null;
|
$toSave['update_date'] = null;
|
||||||
|
|
||||||
if (
|
$toSave['visible'] = $data['visible'];
|
||||||
isset($data['visible']) &&
|
|
||||||
in_array($data['visible'], ['yes', 'on', 1, true])
|
|
||||||
) $toSave['visible'] = true;
|
|
||||||
else $toSave['visible'] = false;
|
|
||||||
|
|
||||||
return $toSave;
|
return $toSave;
|
||||||
}
|
}
|
||||||
|
@@ -12,9 +12,10 @@ return new class extends Migration
|
|||||||
{
|
{
|
||||||
Schema::create('cvs', function (Blueprint $table) {
|
Schema::create('cvs', function (Blueprint $table) {
|
||||||
$table->id();
|
$table->id();
|
||||||
|
$table->string('token', 50);
|
||||||
$table->string('recipient', 255);
|
$table->string('recipient', 255);
|
||||||
$table->string('email', 255);
|
$table->string('email', 255);
|
||||||
$table->string('phone-number', 15);
|
$table->string('phone_number', 15);
|
||||||
$table->json('locations');
|
$table->json('locations');
|
||||||
$table->integer('views')->nullable()->default(0);
|
$table->integer('views')->nullable()->default(0);
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
|
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('cv_infos', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->integer('cv_id')->index();
|
||||||
|
$table->string('ip', 255);
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('cv_infos');
|
||||||
|
}
|
||||||
|
};
|
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('cvs', function (Blueprint $table) {
|
||||||
|
$table->text('mission')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('cvs', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('mission');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('cvs', function (Blueprint $table) {
|
||||||
|
$table->text('rodo')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('cvs', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('rodo');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('cvs', function (Blueprint $table) {
|
||||||
|
$table->string('position', 255)->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('cvs', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('position');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('cvs', function (Blueprint $table) {
|
||||||
|
$table->text('notes')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('cvs', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('notes');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('messages', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('message', 500);
|
||||||
|
$table->string('email', 250);
|
||||||
|
$table->string('sender', 50);
|
||||||
|
$table->softDeletes();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('messages');
|
||||||
|
}
|
||||||
|
};
|
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('cvs', function (Blueprint $table) {
|
||||||
|
$table->boolean('sended')->nullable()->default(false)->after('views');
|
||||||
|
$table->timestamp('sended_timestamp')->nullable()->after('sended');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('cvs', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('sended');
|
||||||
|
$table->dropColumn('sended_timestamp');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
25
database/migrations/2023_08_06_205551_create_notes_table.php
Normal file
25
database/migrations/2023_08_06_205551_create_notes_table.php
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('notes', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('title', 250);
|
||||||
|
$table->text('note');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('notes');
|
||||||
|
}
|
||||||
|
};
|
@@ -1,8 +1,8 @@
|
|||||||
version: "3.9"
|
version: "3.8"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
nginx:
|
nginx:
|
||||||
image: nginx:latest
|
image: nginx:1.21-alpine
|
||||||
container_name: kamilcraft-api_www
|
container_name: kamilcraft-api_www
|
||||||
working_dir: /application
|
working_dir: /application
|
||||||
ports:
|
ports:
|
||||||
@@ -39,7 +39,7 @@ services:
|
|||||||
entrypoint: [ 'npm' ]
|
entrypoint: [ 'npm' ]
|
||||||
ports:
|
ports:
|
||||||
- '3000:3000'
|
- '3000:3000'
|
||||||
- '3001:3001'
|
- '${VITE_PORT:-3001}:${VITE_PORT:-3001}'
|
||||||
volumes:
|
volumes:
|
||||||
- .:/application
|
- .:/application
|
||||||
networks:
|
networks:
|
||||||
@@ -68,5 +68,5 @@ networks:
|
|||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
mysql-db-data:
|
mysql-db-data:
|
||||||
name: ib-mysql-data
|
name: kamilcraft-api-mysql-data
|
||||||
driver: local
|
driver: local
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
FROM php:8.1-fpm-alpine
|
FROM php:8.1-fpm-alpine
|
||||||
|
|
||||||
ARG XDEBUG_VERSION=3.1.6
|
ARG XDEBUG_VERSION=3.2.1
|
||||||
ARG INSTALL_XDEBUG=false
|
ARG INSTALL_XDEBUG=false
|
||||||
|
|
||||||
ARG COMPOSER_VERSION=2.4.4
|
ARG COMPOSER_VERSION=2.5.8
|
||||||
ENV COMPOSER_HOME=/application/.composer
|
ENV COMPOSER_HOME=/application/.composer
|
||||||
ENV COMPOSER_MEMORY_LIMIT=-1
|
ENV COMPOSER_MEMORY_LIMIT=-1
|
||||||
|
|
||||||
|
278
package-lock.json
generated
278
package-lock.json
generated
@@ -5,9 +5,15 @@
|
|||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
||||||
|
"@fortawesome/free-brands-svg-icons": "^6.4.0",
|
||||||
|
"@fortawesome/free-regular-svg-icons": "^6.4.0",
|
||||||
|
"@fortawesome/free-solid-svg-icons": "^6.4.0",
|
||||||
|
"@fortawesome/vue-fontawesome": "^3.0.3",
|
||||||
"@inertiajs/inertia": "^0.11.1",
|
"@inertiajs/inertia": "^0.11.1",
|
||||||
"@inertiajs/inertia-vue3": "^0.6.0",
|
"@inertiajs/inertia-vue3": "^0.6.0",
|
||||||
"@inertiajs/server": "^0.1.0",
|
"@inertiajs/server": "^0.1.0",
|
||||||
|
"@inertiajs/vue3": "^1.0.9",
|
||||||
"@vue/compiler-sfc": "^3.2.45",
|
"@vue/compiler-sfc": "^3.2.45",
|
||||||
"@vue/server-renderer": "^3.2.45",
|
"@vue/server-renderer": "^3.2.45",
|
||||||
"vue": "^3.2.45"
|
"vue": "^3.2.45"
|
||||||
@@ -26,6 +32,15 @@
|
|||||||
"vite-plugin-iso-import": "^1.0.0"
|
"vite-plugin-iso-import": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@aashutoshrathi/word-wrap": {
|
||||||
|
"version": "1.2.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
|
||||||
|
"integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@alloc/quick-lru": {
|
"node_modules/@alloc/quick-lru": {
|
||||||
"version": "5.2.0",
|
"version": "5.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
|
||||||
@@ -39,9 +54,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/parser": {
|
"node_modules/@babel/parser": {
|
||||||
"version": "7.22.5",
|
"version": "7.22.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz",
|
||||||
"integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==",
|
"integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==",
|
||||||
"bin": {
|
"bin": {
|
||||||
"parser": "bin/babel-parser.js"
|
"parser": "bin/babel-parser.js"
|
||||||
},
|
},
|
||||||
@@ -97,23 +112,23 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint-community/regexpp": {
|
"node_modules/@eslint-community/regexpp": {
|
||||||
"version": "4.5.1",
|
"version": "4.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz",
|
||||||
"integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==",
|
"integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
|
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/eslintrc": {
|
"node_modules/@eslint/eslintrc": {
|
||||||
"version": "2.0.3",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz",
|
||||||
"integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==",
|
"integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ajv": "^6.12.4",
|
"ajv": "^6.12.4",
|
||||||
"debug": "^4.3.2",
|
"debug": "^4.3.2",
|
||||||
"espree": "^9.5.2",
|
"espree": "^9.6.0",
|
||||||
"globals": "^13.19.0",
|
"globals": "^13.19.0",
|
||||||
"ignore": "^5.2.0",
|
"ignore": "^5.2.0",
|
||||||
"import-fresh": "^3.2.1",
|
"import-fresh": "^3.2.1",
|
||||||
@@ -129,14 +144,80 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/js": {
|
"node_modules/@eslint/js": {
|
||||||
"version": "8.42.0",
|
"version": "8.44.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.42.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz",
|
||||||
"integrity": "sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==",
|
"integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@fortawesome/fontawesome-common-types": {
|
||||||
|
"version": "6.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.0.tgz",
|
||||||
|
"integrity": "sha512-HNii132xfomg5QVZw0HwXXpN22s7VBHQBv9CeOu9tfJnhsWQNd2lmTNi8CSrnw5B+5YOmzu1UoPAyxaXsJ6RgQ==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@fortawesome/fontawesome-svg-core": {
|
||||||
|
"version": "6.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.0.tgz",
|
||||||
|
"integrity": "sha512-Bertv8xOiVELz5raB2FlXDPKt+m94MQ3JgDfsVbrqNpLU9+UE2E18GKjLKw+d3XbeYPqg1pzyQKGsrzbw+pPaw==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-common-types": "6.4.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@fortawesome/free-brands-svg-icons": {
|
||||||
|
"version": "6.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.4.0.tgz",
|
||||||
|
"integrity": "sha512-qvxTCo0FQ5k2N+VCXb/PZQ+QMhqRVM4OORiO6MXdG6bKolIojGU/srQ1ptvKk0JTbRgaJOfL2qMqGvBEZG7Z6g==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-common-types": "6.4.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@fortawesome/free-regular-svg-icons": {
|
||||||
|
"version": "6.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.4.0.tgz",
|
||||||
|
"integrity": "sha512-ZfycI7D0KWPZtf7wtMFnQxs8qjBXArRzczABuMQqecA/nXohquJ5J/RCR77PmY5qGWkxAZDxpnUFVXKwtY/jPw==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-common-types": "6.4.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@fortawesome/free-solid-svg-icons": {
|
||||||
|
"version": "6.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.4.0.tgz",
|
||||||
|
"integrity": "sha512-kutPeRGWm8V5dltFP1zGjQOEAzaLZj4StdQhWVZnfGFCvAPVvHh8qk5bRrU4KXnRRRNni5tKQI9PBAdI6MP8nQ==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-common-types": "6.4.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@fortawesome/vue-fontawesome": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/vue-fontawesome/-/vue-fontawesome-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-KCPHi9QemVXGMrfuwf3nNnNo129resAIQWut9QTAMXmXqL2ErABC6ohd2yY5Ipq0CLWNbKHk8TMdTXL/Zf3ZhA==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@fortawesome/fontawesome-svg-core": "~1 || ~6",
|
||||||
|
"vue": ">= 3.0.0 < 4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@humanwhocodes/config-array": {
|
"node_modules/@humanwhocodes/config-array": {
|
||||||
"version": "0.11.10",
|
"version": "0.11.10",
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz",
|
||||||
@@ -170,6 +251,17 @@
|
|||||||
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
|
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@inertiajs/core": {
|
||||||
|
"version": "1.0.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@inertiajs/core/-/core-1.0.9.tgz",
|
||||||
|
"integrity": "sha512-Vd/4akXnY90qwtPJ1nVGtLXYhyGZdDjvQ4rv5qeqFYmqLEARdhDd7Lku1BwkboZX6GSTgDkipBSSGTKuRemOkQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.2.0",
|
||||||
|
"deepmerge": "^4.0.0",
|
||||||
|
"nprogress": "^0.2.0",
|
||||||
|
"qs": "^6.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@inertiajs/inertia": {
|
"node_modules/@inertiajs/inertia": {
|
||||||
"version": "0.11.1",
|
"version": "0.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@inertiajs/inertia/-/inertia-0.11.1.tgz",
|
"resolved": "https://registry.npmjs.org/@inertiajs/inertia/-/inertia-0.11.1.tgz",
|
||||||
@@ -209,6 +301,19 @@
|
|||||||
"@inertiajs/inertia": "^0.11.0"
|
"@inertiajs/inertia": "^0.11.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@inertiajs/vue3": {
|
||||||
|
"version": "1.0.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@inertiajs/vue3/-/vue3-1.0.9.tgz",
|
||||||
|
"integrity": "sha512-KoH1KEYxtHs5vbBb3DTTRh9bjFLBakFeqfj95YzwQXkaKaGkE3M79O0n4CaQqG7BSiOdQ3Z3pB2bx+CHpYV9uA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@inertiajs/core": "1.0.9",
|
||||||
|
"lodash.clonedeep": "^4.5.0",
|
||||||
|
"lodash.isequal": "^4.5.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
"node_modules/@jridgewell/gen-mapping": {
|
||||||
"version": "0.3.3",
|
"version": "0.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
||||||
@@ -413,9 +518,9 @@
|
|||||||
"integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ=="
|
"integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ=="
|
||||||
},
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.8.2",
|
"version": "8.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
|
||||||
"integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
|
"integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
@@ -507,8 +612,7 @@
|
|||||||
"node_modules/asynckit": {
|
"node_modules/asynckit": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/autoprefixer": {
|
"node_modules/autoprefixer": {
|
||||||
"version": "10.4.14",
|
"version": "10.4.14",
|
||||||
@@ -547,7 +651,6 @@
|
|||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz",
|
||||||
"integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==",
|
"integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"follow-redirects": "^1.15.0",
|
"follow-redirects": "^1.15.0",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
@@ -660,9 +763,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001503",
|
"version": "1.0.30001517",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001503.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001517.tgz",
|
||||||
"integrity": "sha512-Sf9NiF+wZxPfzv8Z3iS0rXM1Do+iOy2Lxvib38glFX+08TCYYYGR5fRJXk4d77C4AYwhUjgYgMsMudbh2TqCKw==",
|
"integrity": "sha512-Vdhm5S11DaFVLlyiKu4hiUTkpZu+y1KA/rZZqVQfOD5YdDT/eQKlkt7NaE0WGOFgX32diqt9MiP9CAiFeRklaA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -756,7 +859,6 @@
|
|||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"delayed-stream": "~1.0.0"
|
"delayed-stream": "~1.0.0"
|
||||||
},
|
},
|
||||||
@@ -845,7 +947,6 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.4.0"
|
"node": ">=0.4.0"
|
||||||
}
|
}
|
||||||
@@ -875,9 +976,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.4.431",
|
"version": "1.4.473",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.431.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.473.tgz",
|
||||||
"integrity": "sha512-m232JTVmCawA2vG+1azVxhKZ9Sv1Q//xxNv5PkP5rWxGgQE8c3CiZFrh8Xnp+d1NmNxlu3QQrGIfdeW5TtXX5w==",
|
"integrity": "sha512-aVfC8+440vGfl06l8HKKn8/PD5jRfSnLkTTD65EFvU46igbpQRri1gxSzW9/+TeUlwYzrXk1sw867T96zlyECA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/es-module-lexer": {
|
"node_modules/es-module-lexer": {
|
||||||
@@ -1265,15 +1366,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint": {
|
"node_modules/eslint": {
|
||||||
"version": "8.42.0",
|
"version": "8.45.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.42.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.45.0.tgz",
|
||||||
"integrity": "sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==",
|
"integrity": "sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.2.0",
|
"@eslint-community/eslint-utils": "^4.2.0",
|
||||||
"@eslint-community/regexpp": "^4.4.0",
|
"@eslint-community/regexpp": "^4.4.0",
|
||||||
"@eslint/eslintrc": "^2.0.3",
|
"@eslint/eslintrc": "^2.1.0",
|
||||||
"@eslint/js": "8.42.0",
|
"@eslint/js": "8.44.0",
|
||||||
"@humanwhocodes/config-array": "^0.11.10",
|
"@humanwhocodes/config-array": "^0.11.10",
|
||||||
"@humanwhocodes/module-importer": "^1.0.1",
|
"@humanwhocodes/module-importer": "^1.0.1",
|
||||||
"@nodelib/fs.walk": "^1.2.8",
|
"@nodelib/fs.walk": "^1.2.8",
|
||||||
@@ -1285,7 +1386,7 @@
|
|||||||
"escape-string-regexp": "^4.0.0",
|
"escape-string-regexp": "^4.0.0",
|
||||||
"eslint-scope": "^7.2.0",
|
"eslint-scope": "^7.2.0",
|
||||||
"eslint-visitor-keys": "^3.4.1",
|
"eslint-visitor-keys": "^3.4.1",
|
||||||
"espree": "^9.5.2",
|
"espree": "^9.6.0",
|
||||||
"esquery": "^1.4.2",
|
"esquery": "^1.4.2",
|
||||||
"esutils": "^2.0.2",
|
"esutils": "^2.0.2",
|
||||||
"fast-deep-equal": "^3.1.3",
|
"fast-deep-equal": "^3.1.3",
|
||||||
@@ -1295,7 +1396,6 @@
|
|||||||
"globals": "^13.19.0",
|
"globals": "^13.19.0",
|
||||||
"graphemer": "^1.4.0",
|
"graphemer": "^1.4.0",
|
||||||
"ignore": "^5.2.0",
|
"ignore": "^5.2.0",
|
||||||
"import-fresh": "^3.0.0",
|
|
||||||
"imurmurhash": "^0.1.4",
|
"imurmurhash": "^0.1.4",
|
||||||
"is-glob": "^4.0.0",
|
"is-glob": "^4.0.0",
|
||||||
"is-path-inside": "^3.0.3",
|
"is-path-inside": "^3.0.3",
|
||||||
@@ -1305,9 +1405,8 @@
|
|||||||
"lodash.merge": "^4.6.2",
|
"lodash.merge": "^4.6.2",
|
||||||
"minimatch": "^3.1.2",
|
"minimatch": "^3.1.2",
|
||||||
"natural-compare": "^1.4.0",
|
"natural-compare": "^1.4.0",
|
||||||
"optionator": "^0.9.1",
|
"optionator": "^0.9.3",
|
||||||
"strip-ansi": "^6.0.1",
|
"strip-ansi": "^6.0.1",
|
||||||
"strip-json-comments": "^3.1.0",
|
|
||||||
"text-table": "^0.2.0"
|
"text-table": "^0.2.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -1321,9 +1420,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-plugin-vue": {
|
"node_modules/eslint-plugin-vue": {
|
||||||
"version": "9.14.1",
|
"version": "9.15.1",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.15.1.tgz",
|
||||||
"integrity": "sha512-LQazDB1qkNEKejLe/b5a9VfEbtbczcOaui5lQ4Qw0tbRBbQYREyxxOV5BQgNDTqGPs9pxqiEpbMi9ywuIaF7vw==",
|
"integrity": "sha512-CJE/oZOslvmAR9hf8SClTdQ9JLweghT6JCBQNrT2Iel1uVw0W0OLJxzvPd6CxmABKCvLrtyDnqGV37O7KQv6+A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.3.0",
|
"@eslint-community/eslint-utils": "^4.3.0",
|
||||||
@@ -1342,9 +1441,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-scope": {
|
"node_modules/eslint-scope": {
|
||||||
"version": "7.2.0",
|
"version": "7.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.1.tgz",
|
||||||
"integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==",
|
"integrity": "sha512-CvefSOsDdaYYvxChovdrPo/ZGt8d5lrJWleAc1diXRKhHGiTYEI26cvo8Kle/wGnsizoCJjK73FMg1/IkIwiNA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esrecurse": "^4.3.0",
|
"esrecurse": "^4.3.0",
|
||||||
@@ -1370,12 +1469,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/espree": {
|
"node_modules/espree": {
|
||||||
"version": "9.5.2",
|
"version": "9.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
|
||||||
"integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==",
|
"integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": "^8.8.0",
|
"acorn": "^8.9.0",
|
||||||
"acorn-jsx": "^5.3.2",
|
"acorn-jsx": "^5.3.2",
|
||||||
"eslint-visitor-keys": "^3.4.1"
|
"eslint-visitor-keys": "^3.4.1"
|
||||||
},
|
},
|
||||||
@@ -1440,9 +1539,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/fast-glob": {
|
"node_modules/fast-glob": {
|
||||||
"version": "3.2.12",
|
"version": "3.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
|
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
|
||||||
"integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
|
"integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nodelib/fs.stat": "^2.0.2",
|
"@nodelib/fs.stat": "^2.0.2",
|
||||||
@@ -1570,7 +1669,6 @@
|
|||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"asynckit": "^0.4.0",
|
"asynckit": "^0.4.0",
|
||||||
"combined-stream": "^1.0.8",
|
"combined-stream": "^1.0.8",
|
||||||
@@ -1847,9 +1945,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/jiti": {
|
"node_modules/jiti": {
|
||||||
"version": "1.18.2",
|
"version": "1.19.1",
|
||||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz",
|
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.1.tgz",
|
||||||
"integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==",
|
"integrity": "sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"jiti": "bin/jiti.js"
|
"jiti": "bin/jiti.js"
|
||||||
@@ -1973,11 +2071,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/magic-string": {
|
"node_modules/magic-string": {
|
||||||
"version": "0.30.0",
|
"version": "0.30.1",
|
||||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.0.tgz",
|
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.1.tgz",
|
||||||
"integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==",
|
"integrity": "sha512-mbVKXPmS0z0G4XqFDCTllmDQ6coZzn94aMlb0o/A4HEHJCKcanlDZwYJgwnkmgD3jyWhUgj9VsPrfd972yPffA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.13"
|
"@jridgewell/sourcemap-codec": "^1.4.15"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
@@ -2009,7 +2107,6 @@
|
|||||||
"version": "1.52.0",
|
"version": "1.52.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
@@ -2018,7 +2115,6 @@
|
|||||||
"version": "2.1.35",
|
"version": "2.1.35",
|
||||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mime-db": "1.52.0"
|
"mime-db": "1.52.0"
|
||||||
},
|
},
|
||||||
@@ -2079,9 +2175,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/node-releases": {
|
"node_modules/node-releases": {
|
||||||
"version": "2.0.12",
|
"version": "2.0.13",
|
||||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz",
|
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
|
||||||
"integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==",
|
"integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/normalize-path": {
|
"node_modules/normalize-path": {
|
||||||
@@ -2102,6 +2198,11 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/nprogress": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz",
|
||||||
|
"integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA=="
|
||||||
|
},
|
||||||
"node_modules/nth-check": {
|
"node_modules/nth-check": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
|
||||||
@@ -2150,17 +2251,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/optionator": {
|
"node_modules/optionator": {
|
||||||
"version": "0.9.1",
|
"version": "0.9.3",
|
||||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
|
||||||
"integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
|
"integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@aashutoshrathi/word-wrap": "^1.2.3",
|
||||||
"deep-is": "^0.1.3",
|
"deep-is": "^0.1.3",
|
||||||
"fast-levenshtein": "^2.0.6",
|
"fast-levenshtein": "^2.0.6",
|
||||||
"levn": "^0.4.1",
|
"levn": "^0.4.1",
|
||||||
"prelude-ls": "^1.2.1",
|
"prelude-ls": "^1.2.1",
|
||||||
"type-check": "^0.4.0",
|
"type-check": "^0.4.0"
|
||||||
"word-wrap": "^1.2.3"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
@@ -2268,18 +2369,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pirates": {
|
"node_modules/pirates": {
|
||||||
"version": "4.0.5",
|
"version": "4.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
|
||||||
"integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==",
|
"integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.24",
|
"version": "8.4.27",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz",
|
||||||
"integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==",
|
"integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@@ -2418,8 +2519,7 @@
|
|||||||
"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",
|
||||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/punycode": {
|
"node_modules/punycode": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
@@ -2575,9 +2675,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/semver": {
|
"node_modules/semver": {
|
||||||
"version": "7.5.2",
|
"version": "7.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
|
||||||
"integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==",
|
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lru-cache": "^6.0.0"
|
"lru-cache": "^6.0.0"
|
||||||
@@ -2656,9 +2756,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/sucrase": {
|
"node_modules/sucrase": {
|
||||||
"version": "3.32.0",
|
"version": "3.34.0",
|
||||||
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz",
|
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz",
|
||||||
"integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==",
|
"integrity": "sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/gen-mapping": "^0.3.2",
|
"@jridgewell/gen-mapping": "^0.3.2",
|
||||||
@@ -2722,9 +2822,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tailwindcss": {
|
"node_modules/tailwindcss": {
|
||||||
"version": "3.3.2",
|
"version": "3.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.3.tgz",
|
||||||
"integrity": "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==",
|
"integrity": "sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alloc/quick-lru": "^5.2.0",
|
"@alloc/quick-lru": "^5.2.0",
|
||||||
@@ -2747,7 +2847,6 @@
|
|||||||
"postcss-load-config": "^4.0.1",
|
"postcss-load-config": "^4.0.1",
|
||||||
"postcss-nested": "^6.0.1",
|
"postcss-nested": "^6.0.1",
|
||||||
"postcss-selector-parser": "^6.0.11",
|
"postcss-selector-parser": "^6.0.11",
|
||||||
"postcss-value-parser": "^4.2.0",
|
|
||||||
"resolve": "^1.22.2",
|
"resolve": "^1.22.2",
|
||||||
"sucrase": "^3.32.0"
|
"sucrase": "^3.32.0"
|
||||||
},
|
},
|
||||||
@@ -3011,15 +3110,6 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/word-wrap": {
|
|
||||||
"version": "1.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
|
||||||
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
|
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/wrappy": {
|
"node_modules/wrappy": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
|
@@ -7,9 +7,15 @@
|
|||||||
"ssr": "npm run build:ssr && node bootstrap/ssr/ssr.mjs"
|
"ssr": "npm run build:ssr && node bootstrap/ssr/ssr.mjs"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
||||||
|
"@fortawesome/free-brands-svg-icons": "^6.4.0",
|
||||||
|
"@fortawesome/free-regular-svg-icons": "^6.4.0",
|
||||||
|
"@fortawesome/free-solid-svg-icons": "^6.4.0",
|
||||||
|
"@fortawesome/vue-fontawesome": "^3.0.3",
|
||||||
"@inertiajs/inertia": "^0.11.1",
|
"@inertiajs/inertia": "^0.11.1",
|
||||||
"@inertiajs/inertia-vue3": "^0.6.0",
|
"@inertiajs/inertia-vue3": "^0.6.0",
|
||||||
"@inertiajs/server": "^0.1.0",
|
"@inertiajs/server": "^0.1.0",
|
||||||
|
"@inertiajs/vue3": "^1.0.9",
|
||||||
"@vue/compiler-sfc": "^3.2.45",
|
"@vue/compiler-sfc": "^3.2.45",
|
||||||
"@vue/server-renderer": "^3.2.45",
|
"@vue/server-renderer": "^3.2.45",
|
||||||
"vue": "^3.2.45"
|
"vue": "^3.2.45"
|
||||||
|
2
public/.gitignore
vendored
Normal file
2
public/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
hot
|
||||||
|
build/
|
37
resources/js/Pages/CV/ConfirmDelete.vue
Normal file
37
resources/js/Pages/CV/ConfirmDelete.vue
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<script setup>
|
||||||
|
import { router } from '@inertiajs/vue3';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
cv: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
function confirmDelete() {
|
||||||
|
router.delete(`/dashboard/cv/${props.cv.token}/delete`);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<InertiaHead title="Usuwanie CV" />
|
||||||
|
<div class="p-4">
|
||||||
|
<header class="pb-4">
|
||||||
|
<h1 class="text-3xl font-roboto font-light">Usuwanie CV</h1>
|
||||||
|
</header>
|
||||||
|
<div class="max-w-[600px]">
|
||||||
|
<p class="mb-4">Na pewno usunąć CV dla firmy {{ cv.recipient }}?</p>
|
||||||
|
<div class="grid grid-cols-3 gap-2">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
href="/dashboard/cv"
|
||||||
|
class="col-span-1 flex justify-center items-center gap-3 w-full px-2 py-1 border-t-4 border-b-4 border-transparent hover:border-b-black"
|
||||||
|
><FontAwesomeIcon :icon="['fas', 'backward']" />Anuluj</InertiaLink>
|
||||||
|
<button
|
||||||
|
@click.prevent="confirmDelete"
|
||||||
|
class="col-span-2 flex justify-center items-center gap-3 w-full px-2 py-1 rounded-md bg-red-600 border-4 border-red-600 text-white text-lg hover:bg-transparent hover:text-red-600"
|
||||||
|
><FontAwesomeIcon :icon="['fas', 'trash']" /><span class="whitespace-nowrap overflow-hidden overflow-ellipsis">Usuń CV dla firmy {{ cv.recipient }}</span></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
122
resources/js/Pages/CV/Create.vue
Normal file
122
resources/js/Pages/CV/Create.vue
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
<script setup>
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import { useForm } from '@inertiajs/inertia-vue3';
|
||||||
|
import Input from '../../Share/Components/Input.vue';
|
||||||
|
|
||||||
|
const locations = ref([]);
|
||||||
|
const locationsToString = computed({
|
||||||
|
get: () => locations.value.join(', '),
|
||||||
|
set: (val) => {
|
||||||
|
val = val.replace(', ', ',').replace(' , ', ',').replace(' ,', ',');
|
||||||
|
val = val.split(',');
|
||||||
|
val.forEach((element, key) => {
|
||||||
|
val[key] = element.trim();
|
||||||
|
});
|
||||||
|
locations.value = val;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const mission = ref([]);
|
||||||
|
const missionToString = computed({
|
||||||
|
get: () => mission.value.join("\n"),
|
||||||
|
set: (value) => {
|
||||||
|
mission.value = value.split("\n");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const form = useForm({
|
||||||
|
recipient: null,
|
||||||
|
email: null,
|
||||||
|
phone_number: null,
|
||||||
|
locations: locations,
|
||||||
|
mission: missionToString,
|
||||||
|
rodo: null,
|
||||||
|
position: null,
|
||||||
|
notes: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
function createCV() {
|
||||||
|
form.post('/dashboard/cv');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<InertiaHead title="Nowe dane do CV" />
|
||||||
|
<div class="p-4">
|
||||||
|
<header class="pb-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
href="/dashboard/cv"
|
||||||
|
class="px-2 text-xl text-gray-700 hover:text-black"
|
||||||
|
title="Wróć do listy CV"><FontAwesomeIcon :icon="['fas', 'caret-left']" /></InertiaLink>
|
||||||
|
<h1 class="text-3xl font-roboto font-light">Nowe dane do CV</h1>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div>
|
||||||
|
<form class="flex flex-col gap-4" @submit.prevent="createCV">
|
||||||
|
<Input
|
||||||
|
id="recipient"
|
||||||
|
label="Firma gdzie jest składane CV"
|
||||||
|
placeholder="Oki doki sp. z.o.o"
|
||||||
|
v-model="form.recipient"
|
||||||
|
:error="form.errors.recipient"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="email"
|
||||||
|
type="email"
|
||||||
|
label="E-mail"
|
||||||
|
placeholder="Adres e-mail wyświetlany na CV"
|
||||||
|
v-model="form.email"
|
||||||
|
:error="form.errors.email"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="phone"
|
||||||
|
label="Numer telefonu"
|
||||||
|
placeholder="+48 123 456 789"
|
||||||
|
v-model="form.phone_number"
|
||||||
|
:error="form.errors.phone_number"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="locations"
|
||||||
|
label="Lokalizacje"
|
||||||
|
placeholder="Miejsca pracy."
|
||||||
|
v-model="locationsToString"
|
||||||
|
:error="form.errors.locations"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="position"
|
||||||
|
label="Stanowisko (opcjonalne)"
|
||||||
|
placeholder="Stanowisko na jakie jest rekrutacja."
|
||||||
|
v-model="form.position"
|
||||||
|
:error="form.errors.position"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="notes"
|
||||||
|
type="textarea"
|
||||||
|
label="Notatki (opcjonalne)"
|
||||||
|
placeholder="Notatka dla administratora"
|
||||||
|
v-model="form.notes"
|
||||||
|
:error="form.errors.notes"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="mission"
|
||||||
|
type="textarea"
|
||||||
|
label="Misja - wstęp (opcjonalne)"
|
||||||
|
placeholder="Krótki opis, list motywacyjny."
|
||||||
|
v-model="form.mission"
|
||||||
|
:error="form.errors.mission"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="rodo"
|
||||||
|
type="textarea"
|
||||||
|
label="RODO (opcjonalne)"
|
||||||
|
placeholder="Klauzula informacyjna RODO"
|
||||||
|
v-model="form.rodo"
|
||||||
|
:error="form.errors.rodo"
|
||||||
|
/>
|
||||||
|
<button class="px-0.5 py-1 rounded-lg bg-[#436da7] border-4 border-[#436da7] text-white text-lg hover:bg-transparent hover:text-[#436da7]">Utwórz nowe CV</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
149
resources/js/Pages/CV/Edit.vue
Normal file
149
resources/js/Pages/CV/Edit.vue
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
<script setup>
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import { useForm } from '@inertiajs/inertia-vue3';
|
||||||
|
import Input from '../../Share/Components/Input.vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
cv: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const locations = ref(props.cv.locations);
|
||||||
|
const locationsToString = computed({
|
||||||
|
get: () => locations.value.join(', '),
|
||||||
|
set: (val) => {
|
||||||
|
val = val.replace(', ', ',').replace(' , ', ',').replace(' ,', ',');
|
||||||
|
val = val.split(',');
|
||||||
|
val.forEach((element, key) => {
|
||||||
|
val[key] = element.trim();
|
||||||
|
});
|
||||||
|
locations.value = val;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const mission = ref(props.cv.mission);
|
||||||
|
const missionToString = computed({
|
||||||
|
get: () => mission.value.join("\n"),
|
||||||
|
set: (value) => {
|
||||||
|
mission.value = value.split("\n");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const form = useForm({
|
||||||
|
recipient: props.cv.recipient,
|
||||||
|
email: props.cv.email,
|
||||||
|
phone_number: props.cv.phone.formattedNumber,
|
||||||
|
locations: locations,
|
||||||
|
mission: missionToString,
|
||||||
|
rodo: props.cv.rodo,
|
||||||
|
position: props.cv.position,
|
||||||
|
notes: props.cv.notes,
|
||||||
|
sended: props.cv.sended.status,
|
||||||
|
});
|
||||||
|
|
||||||
|
function updateCV() {
|
||||||
|
form.put(`/dashboard/cv/${props.cv.token}`);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<InertiaHead title="Edycja danych do CV" />
|
||||||
|
<div class="p-4">
|
||||||
|
<header class="flex items-center justify-between pb-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
href="/dashboard/cv"
|
||||||
|
class="px-2 text-xl text-gray-700 hover:text-black"
|
||||||
|
title="Wróć do listy CV"><FontAwesomeIcon :icon="['fas', 'caret-left']" /></InertiaLink>
|
||||||
|
<h1 class="text-3xl font-roboto font-light">Edycja danych do CV</h1>
|
||||||
|
</div>
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
:href="`/dashboard/cv/${cv.token}/delete`"
|
||||||
|
class="flex items-center gap-2 px-2 py-1 text-red-600 hover:text-white hover:bg-red-600 rounded-md"
|
||||||
|
title="Usuń CV"
|
||||||
|
><FontAwesomeIcon :icon="['fas', 'trash']" />Usuń</InertiaLink>
|
||||||
|
</header>
|
||||||
|
<div>
|
||||||
|
<form class="flex flex-col gap-4" @submit.prevent="updateCV">
|
||||||
|
<Input
|
||||||
|
id="recipient"
|
||||||
|
label="Firma gdzie jest składane CV"
|
||||||
|
placeholder="Oki doki sp. z.o.o"
|
||||||
|
v-model="form.recipient"
|
||||||
|
:error="form.errors.recipient"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="email"
|
||||||
|
type="email"
|
||||||
|
label="E-mail"
|
||||||
|
placeholder="Adres e-mail wyświetlany na CV"
|
||||||
|
v-model="form.email"
|
||||||
|
:error="form.errors.email"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="phone"
|
||||||
|
label="Numer telefonu"
|
||||||
|
placeholder="+48 123 456 789"
|
||||||
|
v-model="form.phone_number"
|
||||||
|
:error="form.errors.phone_number"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="locations"
|
||||||
|
label="Lokalizacje"
|
||||||
|
placeholder="Miejsca pracy."
|
||||||
|
v-model="locationsToString"
|
||||||
|
:error="form.errors.locations"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="position"
|
||||||
|
label="Stanowisko"
|
||||||
|
placeholder="Stanowisko na jakie jest rekrutacja."
|
||||||
|
v-model="form.position"
|
||||||
|
:error="form.errors.position"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="notes"
|
||||||
|
type="textarea"
|
||||||
|
label="Notatki (opcjonalne)"
|
||||||
|
placeholder="Notatka dla administratora"
|
||||||
|
v-model="form.notes"
|
||||||
|
:error="form.errors.notes"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="mission"
|
||||||
|
type="textarea"
|
||||||
|
label="Misja - wstęp"
|
||||||
|
placeholder="Krótki opis, list motywacyjny."
|
||||||
|
v-model="form.mission"
|
||||||
|
:error="form.errors.mission"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="rodo"
|
||||||
|
type="textarea"
|
||||||
|
label="RODO"
|
||||||
|
placeholder="Klauzula informacyjna RODO"
|
||||||
|
v-model="form.rodo"
|
||||||
|
:error="form.errors.rodo"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="sended"
|
||||||
|
label="Wysłany"
|
||||||
|
type="checkbox"
|
||||||
|
v-model="form.sended"
|
||||||
|
/>
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-3 sm:gap-2 items-center">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
:href="`/dashboard/cv/${cv.token}`"
|
||||||
|
class="col-span-1 flex justify-center items-center gap-3 w-full px-2 py-1 border-t-4 border-b-4 border-transparent hover:border-b-black"
|
||||||
|
><FontAwesomeIcon :icon="['fas', 'backward']" />Anuluj</InertiaLink>
|
||||||
|
<button class="col-span-1 md:col-span-2 px-0.5 py-1 rounded-lg bg-[#436da7] border-4 border-[#436da7] text-white text-lg hover:bg-transparent hover:text-[#436da7]">Edytuj CV</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
93
resources/js/Pages/CV/Index.vue
Normal file
93
resources/js/Pages/CV/Index.vue
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
<script setup>
|
||||||
|
import EmptyState from '@/Share/Components/EmptyState.vue';
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
cvs: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function copySlug(slug) {
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.value = slug;
|
||||||
|
input.select();
|
||||||
|
input.setSelectionRange(0, 99999);
|
||||||
|
|
||||||
|
navigator
|
||||||
|
.clipboard
|
||||||
|
.writeText(input.value)
|
||||||
|
.then((value, reason) => { });
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<InertiaHead title="Lista CV" />
|
||||||
|
<div class="p-4">
|
||||||
|
<header class="flex justify-between items-center pb-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
href="/dashboard"
|
||||||
|
class="px-2 text-xl text-gray-700 hover:text-black"
|
||||||
|
title="Wróc do dashboard"><FontAwesomeIcon :icon="['fas', 'caret-left']" /></InertiaLink>
|
||||||
|
<h1 class="text-3xl font-roboto font-light">Lista CV</h1>
|
||||||
|
</div>
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
href="/dashboard/cv/create"
|
||||||
|
class="bg-blue-400 hover:bg-blue-500 text-white px-2.5 py-1 rounded-full"
|
||||||
|
title="Dodaj nowe dane dla CV"
|
||||||
|
><FontAwesomeIcon :icon="['fas', 'plus']" /></InertiaLink>
|
||||||
|
</header>
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table v-if="cvs.data.length" class="w-full min-w-[600px] border-separate border-spacing-y-2 cursor-pointer">
|
||||||
|
<colgroup>
|
||||||
|
<col class="w-min" />
|
||||||
|
</colgroup>
|
||||||
|
<thead class="text-left bg-gray-100">
|
||||||
|
<th class="p-2 text-center">ID</th>
|
||||||
|
<th class="p-2">Token</th>
|
||||||
|
<th class="w-[100px] p-2 whitespace-nowrap">Firma</th>
|
||||||
|
<th class="hidden md:table-cell p-2">Lokalizacje</th>
|
||||||
|
<th class="p-2">Telefon</th>
|
||||||
|
<th class="p-2"></th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<InertiaLink
|
||||||
|
as="tr"
|
||||||
|
v-for="(cv, key) in cvs.data"
|
||||||
|
:key="key"
|
||||||
|
class="px-3 py-2 bg-white hover:bg-neutral-200 rounded-md z-10"
|
||||||
|
:href="`/dashboard/cv/${cv.token}`">
|
||||||
|
<td class="p-2 text-center">#{{ cv.id }}</td>
|
||||||
|
<td class="p-2"
|
||||||
|
><button
|
||||||
|
class="bg-gray-50 p-1 rounded-md hover:bg-gray-100"
|
||||||
|
@click.prevent="copySlug(cv.token)"
|
||||||
|
:title="cv.token">{{ cv.token.slice(0, 7) }}</button></td>
|
||||||
|
<td class="max-w-[150px] md:max-w-[250px] p-2 whitespace-nowrap overflow-hidden overflow-ellipsis" :title="cv.recipient">{{ cv.recipient }}</td>
|
||||||
|
<td class="hidden md:table-cell p-2">{{ cv.locations.join(' / ') }}</td>
|
||||||
|
<td class="p-2">{{ cv.phone.formattedNumber }}</td>
|
||||||
|
<td class="flex items-center justify-center gap-2 p-3 z-50">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
class="px-3 py-3 text-lime-600 hover:text-lime-800 border-t-2 border-b-2 border-transparent hover:border-b-lime-600"
|
||||||
|
:href="`/dashboard/cv/${cv.token}/edit`"
|
||||||
|
title="Edytuj CV"><FontAwesomeIcon :icon="['fas', 'pen-to-square']" /></InertiaLink>
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
class="px-3 py-3 text-red-600 hover:text-red-800"
|
||||||
|
:href="`/dashboard/cv/${cv.token}/delete`"
|
||||||
|
title="Usuń CV z listy"><FontAwesomeIcon :icon="['fas', 'trash']" /></InertiaLink>
|
||||||
|
</td>
|
||||||
|
</InertiaLink>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<EmptyState v-else :icon="['fas', 'file']">
|
||||||
|
<template #title>Nie znaleziono</template>
|
||||||
|
<template #text>Nie dodano jeszcze CV do listy.</template>
|
||||||
|
</EmptyState>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
169
resources/js/Pages/CV/Show.vue
Normal file
169
resources/js/Pages/CV/Show.vue
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import { router } from '@inertiajs/inertia';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
cv: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
cvInfo: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const CV_URL = import.meta.env.VITE_CV_APP_URL;
|
||||||
|
const cvNotes = computed(() => {
|
||||||
|
const notes = props.cv.notes;
|
||||||
|
return notes ? props.cv.notes.split("\n") : null;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<InertiaHead title="Szczegóły CV" />
|
||||||
|
<div class="px-3 py-2">
|
||||||
|
<InertiaLink
|
||||||
|
v-if="!cv.sended.status"
|
||||||
|
as="button"
|
||||||
|
method="post"
|
||||||
|
:href="`/dashboard/cv/${cv.token}/sended`"
|
||||||
|
class="w-full px-0.5 py-1 rounded-lg bg-[#436da7] border-4 border-[#436da7] text-white text-lg hover:bg-transparent hover:text-[#436da7]"
|
||||||
|
title="Ustaw jako wysłane">Ustaw jako wysłane do odbiorcy.</InertiaLink>
|
||||||
|
</div>
|
||||||
|
<div class="p-4">
|
||||||
|
<header class="flex justify-between items-center pb-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
href="/dashboard/cv"
|
||||||
|
class="px-2 text-xl text-gray-700 hover:text-black"
|
||||||
|
title="Wróć do listy CV"><FontAwesomeIcon :icon="['fas', 'caret-left']" /></InertiaLink>
|
||||||
|
<h1 class="text-3xl font-roboto font-light">Szczegóły CV</h1>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-3 sm:gap-2">
|
||||||
|
<a
|
||||||
|
class="flex items-center gap-2 px-2 py-1 text-blue-600 hover:text-blue-800"
|
||||||
|
:href="`${CV_URL}/show/${cv.token}`"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
title="Przekieruj do CV"><FontAwesomeIcon :icon="['fas', 'arrow-up-right-from-square']" /><span class="hidden sm:inline-block">Przejdź do CV</span></a>
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
:href="`/dashboard/cv/${cv.token}/edit`"
|
||||||
|
class="flex items-center gap-2 px-2 py-1 text-lime-600 hover:text-white hover:bg-lime-600 rounded-md"
|
||||||
|
title="Usuń CV"
|
||||||
|
><FontAwesomeIcon :icon="['fas', 'pen-to-square']" /><span class="hidden sm:inline-block">Edytuj</span></InertiaLink>
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
:href="`/dashboard/cv/${cv.token}/delete`"
|
||||||
|
class="flex items-center gap-2 px-2 py-1 text-red-600 hover:text-white hover:bg-red-600 rounded-md"
|
||||||
|
title="Usuń CV"
|
||||||
|
><FontAwesomeIcon :icon="['fas', 'trash']" /><span class="hidden sm:inline-block">Usuń</span></InertiaLink>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div v-if="cv.sended.status" class="max-w-screen-lg my-2 lg:mx-auto px-2 py-3 rounded-md bg-yellow-100 text-yellow-600 text-center">
|
||||||
|
CV jest oznaczone jako wysłane - {{ cv.sended.datetime }}
|
||||||
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<header>
|
||||||
|
<h2 class="text-2xl font-roboto font-light pb-3">Podstawowe informacje</h2>
|
||||||
|
</header>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<div class="text-gray-500 pb-0.5">Token</div>
|
||||||
|
<p class="w-full min-w-full max-w-full px-2.5 py-2 border-b-2 rounded-md bg-white whitespace-nowrap overflow-hidden overflow-ellipsis">{{ cv.token }}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-gray-500 pb-0.5">Firma</div>
|
||||||
|
<p class="w-full min-w-full max-w-full px-2.5 py-2 border-b-2 rounded-md bg-white">{{ cv.recipient }}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-gray-500 pb-0.5">Stanowisko</div>
|
||||||
|
<p class="w-full min-w-full max-w-full px-2.5 py-2 border-b-2 rounded-md bg-white">{{ cv.position ?? '[Wartość domyślna]' }}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-gray-500 pb-0.5">E-mail</div>
|
||||||
|
<p class="w-full min-w-full max-w-full px-2.5 py-2 border-b-2 rounded-md bg-white">{{ cv.email }}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-gray-500 pb-0.5">Numer telefonu</div>
|
||||||
|
<p class="w-full min-w-full max-w-full px-2.5 py-2 border-b-2 rounded-md bg-white">{{ cv.phone.formattedNumber }}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-gray-500 pb-0.5">Lokalizacje</div>
|
||||||
|
<p class="w-full min-w-full max-w-full px-2.5 py-2 border-b-2 rounded-md bg-white">{{ cv.locations.join(' / ') }}</p>
|
||||||
|
</div>
|
||||||
|
<div v-if="cvNotes" class="md:col-span-2">
|
||||||
|
<div class="text-gray-500 pb-0.5">Notatki</div>
|
||||||
|
<div class="w-full min-w-full max-w-full px-2.5 py-2 border-b-2 rounded-md bg-white">
|
||||||
|
<p
|
||||||
|
v-for="(noteLine, key) in cvNotes"
|
||||||
|
:key="key"
|
||||||
|
>{{ noteLine }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<header>
|
||||||
|
<h2 class="text-2xl font-roboto font-light pb-3">Statystyka</h2>
|
||||||
|
</header>
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<div class="text-gray-500 pb-0.5">Utworzono</div>
|
||||||
|
<p class="w-full min-w-full max-w-full px-2.5 py-2 border-b-2 rounded-md bg-white">{{ cv.created }}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-gray-500 pb-0.5">Zmodyfikowano</div>
|
||||||
|
<p class="w-full min-w-full max-w-full px-2.5 py-2 border-b-2 rounded-md bg-white">{{ cv.updated }}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-gray-500 pb-0.5">Zachowane wyświetlenia</div>
|
||||||
|
<p class="w-full min-w-full max-w-full px-2.5 py-2 border-b-2 rounded-md bg-white">{{ cv.views }}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-gray-500 pb-0.5">Łączne wyświetlenia</div>
|
||||||
|
<p class="w-full min-w-full max-w-full px-2.5 py-2 border-b-2 rounded-md bg-white">{{ cv.registeredViews }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<header>
|
||||||
|
<h2 class="text-2xl font-roboto font-light pb-3">Opisy</h2>
|
||||||
|
</header>
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<div class="text-gray-500 pb-0.5">Misja</div>
|
||||||
|
<div v-if="cv.mission.length > 0 && cv.mission[0] !== ''" class="w-full min-w-full max-w-full px-2.5 py-2 border-b-2 rounded-md bg-white">
|
||||||
|
<p
|
||||||
|
v-for="(mission, key) in cv.mission"
|
||||||
|
:key="key">{{ mission }}</p>
|
||||||
|
</div>
|
||||||
|
<p v-else class="w-full min-w-full max-w-full px-2.5 py-2 border-b-2 rounded-md bg-white">[Wartość domyślna]</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-gray-500 pb-0.5">RODO</div>
|
||||||
|
<p class="w-full min-w-full max-w-full px-2.5 py-2 border-b-2 rounded-md bg-white">{{ cv.rodo ?? '[Wartość domyślna]' }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<header>
|
||||||
|
<h2 class="text-2xl font-roboto font-light pb-3">Lista wejść</h2>
|
||||||
|
</header>
|
||||||
|
<ul v-if="cvInfo.data.length" class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-2">
|
||||||
|
<li
|
||||||
|
v-for="(info, key) in cvInfo.data"
|
||||||
|
:key="key"
|
||||||
|
class="flex flex-col px-3 py-2 bg-white rounded-md">
|
||||||
|
<span>#{{ info.id }} {{ info.ip }}</span>
|
||||||
|
<span class="text-xs">{{ info.created_at }}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div v-else>
|
||||||
|
Brak wyświetleń
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
37
resources/js/Pages/Categories/ConfirmDelete.vue
Normal file
37
resources/js/Pages/Categories/ConfirmDelete.vue
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<script setup>
|
||||||
|
import { router } from '@inertiajs/vue3';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
category: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
function confirmDelete() {
|
||||||
|
router.delete(`/dashboard/category/${props.category.id}/delete`);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<InertiaHead title="Usuwanie kategorii" />
|
||||||
|
<div class="p-4">
|
||||||
|
<header class="pb-4">
|
||||||
|
<h1 class="text-3xl font-roboto font-light">Usuwanie kategorii</h1>
|
||||||
|
</header>
|
||||||
|
<div class="max-w-[600px]">
|
||||||
|
<p class="mb-4">Na pewno usunąć kategorię o nazwie {{ category.name }}?</p>
|
||||||
|
<div class="grid grid-cols-3 gap-2">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
href="/dashboard"
|
||||||
|
class="col-span-1 flex justify-center items-center gap-3 w-full px-2 py-1 border-t-4 border-b-4 border-transparent hover:border-b-black"
|
||||||
|
><FontAwesomeIcon :icon="['fas', 'backward']" />Anuluj</InertiaLink>
|
||||||
|
<button
|
||||||
|
@click.prevent="confirmDelete"
|
||||||
|
class="col-span-2 flex justify-center items-center gap-3 w-full px-2 py-1 rounded-md bg-red-600 border-4 border-red-600 text-white text-lg hover:bg-transparent hover:text-red-600"
|
||||||
|
><FontAwesomeIcon :icon="['fas', 'trash']" />Usuń kategorię {{ category.name }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
71
resources/js/Pages/Categories/Create.vue
Normal file
71
resources/js/Pages/Categories/Create.vue
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<script setup>
|
||||||
|
import { useForm } from '@inertiajs/inertia-vue3';
|
||||||
|
import Input from '../../Share/Components/Input.vue';
|
||||||
|
|
||||||
|
const form = useForm({
|
||||||
|
name: null,
|
||||||
|
slug: null,
|
||||||
|
priority: Number(0),
|
||||||
|
default: Boolean(false),
|
||||||
|
visible: Boolean(false),
|
||||||
|
});
|
||||||
|
|
||||||
|
function createCategory() {
|
||||||
|
form.post('/dashboard/category');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<InertiaHead title="Nowa kategoria" />
|
||||||
|
<div class="p-4">
|
||||||
|
<header class="pb-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
href="/dashboard"
|
||||||
|
class="px-2 text-xl text-gray-700 hover:text-black"
|
||||||
|
title="Wróc do dashboard"><FontAwesomeIcon :icon="['fas', 'caret-left']" /></InertiaLink>
|
||||||
|
<h1 class="text-3xl font-roboto font-light">Nowa kategoria</h1>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div>
|
||||||
|
<form class="flex flex-col gap-4" @submit.prevent="createCategory">
|
||||||
|
<Input
|
||||||
|
id="name"
|
||||||
|
label="Nazwa"
|
||||||
|
placeholder="Nazwa kategorii"
|
||||||
|
v-model="form.name"
|
||||||
|
:error="form.errors.name"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="slug"
|
||||||
|
label="Slug"
|
||||||
|
placeholder="Slug dla kategorii"
|
||||||
|
v-model="form.slug"
|
||||||
|
:error="form.errors.slug"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="priority"
|
||||||
|
label="Priorytet"
|
||||||
|
type="number"
|
||||||
|
placeholder="Priorytet dla danej kategorii"
|
||||||
|
v-model="form.priority"
|
||||||
|
:error="form.errors.priority"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="visible"
|
||||||
|
label="Widoczny"
|
||||||
|
type="checkbox"
|
||||||
|
v-model="form.visible"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="default"
|
||||||
|
label="Domyślny"
|
||||||
|
type="checkbox"
|
||||||
|
v-model="form.default"
|
||||||
|
/>
|
||||||
|
<button class="px-0.5 py-1 rounded-lg bg-[#436da7] border-4 border-[#436da7] text-white text-lg hover:bg-transparent hover:text-[#436da7]">Dodaj kategorię</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
91
resources/js/Pages/Categories/Edit.vue
Normal file
91
resources/js/Pages/Categories/Edit.vue
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { useForm } from '@inertiajs/inertia-vue3';
|
||||||
|
import Input from '../../Share/Components/Input.vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
category: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const visibleCheckbox = ref(props.category.visible);
|
||||||
|
const defaultCheckbox = ref(props.category.default);
|
||||||
|
|
||||||
|
const form = useForm({
|
||||||
|
name: props.category.name,
|
||||||
|
slug: props.category.slug,
|
||||||
|
priority: props.category.priority,
|
||||||
|
visible: visibleCheckbox,
|
||||||
|
default: defaultCheckbox,
|
||||||
|
});
|
||||||
|
|
||||||
|
function updateProject() {
|
||||||
|
form.clearErrors();
|
||||||
|
form.put(`/dashboard/category/${props.category.id}`);
|
||||||
|
if (defaultCheckbox.value)
|
||||||
|
visibleCheckbox.value = true;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<InertiaHead title="Edytuj projekt" />
|
||||||
|
<div class="p-4">
|
||||||
|
<header class="flex items-center justify-between pb-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
href="/dashboard"
|
||||||
|
class="px-2 text-xl text-gray-700 hover:text-black"
|
||||||
|
title="Wróc do dashboard"><FontAwesomeIcon :icon="['fas', 'caret-left']" /></InertiaLink>
|
||||||
|
<h1 class="text-3xl font-roboto font-light">Edytuj {{ category.name }}</h1>
|
||||||
|
</div>
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
:href="`/dashboard/category/${category.id}/delete`"
|
||||||
|
class="flex items-center gap-2 px-2 py-1 text-red-600 hover:text-white hover:bg-red-600 rounded-md"
|
||||||
|
title="Usuń kategorię"
|
||||||
|
><FontAwesomeIcon :icon="['fas', 'trash']" />Usuń</InertiaLink>
|
||||||
|
</header>
|
||||||
|
<div>
|
||||||
|
<form class="flex flex-col gap-4" @submit.prevent="updateProject">
|
||||||
|
<Input
|
||||||
|
id="name"
|
||||||
|
label="Nazwa"
|
||||||
|
placeholder="Nazwa kategorii"
|
||||||
|
v-model="form.name"
|
||||||
|
:error="form.errors.name"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="slug"
|
||||||
|
label="Slug"
|
||||||
|
placeholder="Slug dla kategorii"
|
||||||
|
v-model="form.slug"
|
||||||
|
:error="form.errors.slug"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="priority"
|
||||||
|
label="Priorytet"
|
||||||
|
type="number"
|
||||||
|
placeholder="Priorytet dla danej kategorii"
|
||||||
|
v-model="form.priority"
|
||||||
|
:error="form.errors.priority"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="visible"
|
||||||
|
label="Widoczny"
|
||||||
|
type="checkbox"
|
||||||
|
v-model="form.visible"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="default"
|
||||||
|
label="Domyślny"
|
||||||
|
type="checkbox"
|
||||||
|
v-model="form.default"
|
||||||
|
/>
|
||||||
|
<button class="px-0.5 py-1 rounded-lg bg-[#436da7] border-4 border-[#436da7] text-white text-lg hover:bg-transparent hover:text-[#436da7]">Aktualizuj kategorię</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
28
resources/js/Pages/Dashboard/Index.vue
Normal file
28
resources/js/Pages/Dashboard/Index.vue
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<script setup>
|
||||||
|
import ProjectsList from '../../Share/ProjectsList.vue';
|
||||||
|
import CategoriesList from '../../Share/CategoriesList.vue';
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
categories: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
projects: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<InertiaHead title="Dashboard" />
|
||||||
|
<div class="p-4">
|
||||||
|
<header class="pb-4">
|
||||||
|
<h1 class="text-3xl font-roboto font-light">Dashboard</h1>
|
||||||
|
</header>
|
||||||
|
<div class="grid md:grid-cols-3 gap-3">
|
||||||
|
<ProjectsList class="md:col-span-2" :projects="projects" />
|
||||||
|
<CategoriesList class="col-span-1" :categories="categories" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
45
resources/js/Pages/Login.vue
Normal file
45
resources/js/Pages/Login.vue
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<script setup>
|
||||||
|
import { useForm } from '@inertiajs/inertia-vue3';
|
||||||
|
import GuestLayout from '../Share/Layout/Guest.vue';
|
||||||
|
|
||||||
|
defineOptions({ layout: GuestLayout });
|
||||||
|
|
||||||
|
const form = useForm({
|
||||||
|
'email': null,
|
||||||
|
'password': null,
|
||||||
|
});
|
||||||
|
|
||||||
|
function login() {
|
||||||
|
form.post('/dashboard/login');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<InertiaHead title="Logowanie" />
|
||||||
|
<div class="max-w-screen-sm mx-auto p-4 bg-neutral-100 rounded-md border border-gray-200 shadow">
|
||||||
|
<h1 class="pb-4 text-3xl font-robot font-light">Logowanie</h1>
|
||||||
|
<form class="flex flex-col gap-4" @submit.prevent="form.post('/dashboard/login')">
|
||||||
|
<div class="flex flex-col gap-1 w-full">
|
||||||
|
<label for="email"
|
||||||
|
class="text-gray-500">E-mail</label>
|
||||||
|
<input id="email"
|
||||||
|
:class="['w-full px-2.5 py-2 border-b-2 rounded-md', form.errors.email ? 'border-red-300 focus:border-red-400 hover:border-red-500 outline-none text-red-900 placeholder-red-400' : 'border-neutral-300 focus:border-neutral-400 hover:border-neutral-500 outline-none text-gray-900 placeholder-gray-400']"
|
||||||
|
type="email"
|
||||||
|
v-model="form.email"
|
||||||
|
placeholder="Podaj swój e-mail" />
|
||||||
|
<span class="text-red-400" v-if="form.errors.email">{{ form.errors.email }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<label for="password"
|
||||||
|
class="text-gray-500">Hasło</label>
|
||||||
|
<input
|
||||||
|
id="password"
|
||||||
|
:class="['w-full px-2.5 py-2 border-b-2 rounded-md', form.errors.email ? 'border-red-300 focus:border-red-400 hover:border-red-500 outline-none text-red-900 placeholder-red-400' : 'border-neutral-300 focus:border-neutral-400 hover:border-neutral-500 outline-none text-gray-900 placeholder-gray-400']"
|
||||||
|
type="password"
|
||||||
|
v-model="form.password"
|
||||||
|
placeholder="Podaj swoje hasło" />
|
||||||
|
</div>
|
||||||
|
<button class="px-0.5 py-1 rounded-lg bg-[#436da7] border-4 border-[#436da7] text-white text-lg hover:bg-transparent hover:text-[#436da7]">Zaloguj</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</template>
|
37
resources/js/Pages/Messages/ConfirmDelete.vue
Normal file
37
resources/js/Pages/Messages/ConfirmDelete.vue
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<script setup>
|
||||||
|
import { router } from '@inertiajs/vue3';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
message: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
function confirmDelete() {
|
||||||
|
router.delete(`/dashboard/message/${props.message.id}/delete`);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<InertiaHead title="Usuwanie wiadomości" />
|
||||||
|
<div class="p-4">
|
||||||
|
<header class="pb-4">
|
||||||
|
<h1 class="text-3xl font-roboto font-light">Usuwanie wiadomości</h1>
|
||||||
|
</header>
|
||||||
|
<div class="max-w-[600px]">
|
||||||
|
<p class="mb-4">Na pewno usunąć wiadomość od {{ message.sender }}?</p>
|
||||||
|
<div class="grid grid-cols-3 gap-2">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
:href="`/dashboard/message/${message.id}`"
|
||||||
|
class="col-span-1 flex justify-center items-center gap-3 w-full px-2 py-1 border-t-4 border-b-4 border-transparent hover:border-b-black"
|
||||||
|
><FontAwesomeIcon :icon="['fas', 'backward']" />Anuluj</InertiaLink>
|
||||||
|
<button
|
||||||
|
@click.prevent="confirmDelete"
|
||||||
|
class="col-span-2 flex justify-center items-center gap-3 w-full px-2 py-1 rounded-md bg-red-600 border-4 border-red-600 text-white text-lg hover:bg-transparent hover:text-red-600"
|
||||||
|
><FontAwesomeIcon :icon="['fas', 'trash']" /><span class="whitespace-nowrap overflow-hidden overflow-ellipsis">Usuń wiadomość od {{ message.sender }}</span></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
65
resources/js/Pages/Messages/Index.vue
Normal file
65
resources/js/Pages/Messages/Index.vue
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
<script setup>
|
||||||
|
import EmptyState from '@/Share/Components/EmptyState.vue';
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
messages: {
|
||||||
|
type: Object,
|
||||||
|
default: {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<InertiaHead title="Wiadomości" />
|
||||||
|
<div class="p-4">
|
||||||
|
<header class="flex justify-between items-center pb-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
href="/dashboard"
|
||||||
|
class="px-2 text-xl text-gray-700 hover:text-black"
|
||||||
|
title="Wróc do dashboard"><FontAwesomeIcon :icon="['fas', 'caret-left']" /></InertiaLink>
|
||||||
|
<h1 class="text-3xl font-roboto font-light">Wiadomości</h1>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table v-if="messages.data.length" class="table-fixed w-full min-w-[600px] border-separate border-spacing-y-2 cursor-pointer">
|
||||||
|
<colgroup>
|
||||||
|
<col class="w-[40px] max-w-[60px]" />
|
||||||
|
<col class="w-[250px]" />
|
||||||
|
<col class="w-auto" />
|
||||||
|
<col class="w-[50px]" />
|
||||||
|
</colgroup>
|
||||||
|
<thead class="text-left bg-gray-100">
|
||||||
|
<th class="w-[40px] max-w-[60px] p-2 text-center">ID</th>
|
||||||
|
<th class="w-[250px] p-2">Wysyłający</th>
|
||||||
|
<th class="p-2">E-mail</th>
|
||||||
|
<th class="w-[50px] p-2"></th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<InertiaLink
|
||||||
|
as="tr"
|
||||||
|
v-for="(message, key) in messages.data"
|
||||||
|
:key="key"
|
||||||
|
class="px-3 py-2 bg-white hover:bg-neutral-200 rounded-md z-10"
|
||||||
|
:href="`/dashboard/message/${message.id}`">
|
||||||
|
<td class="p-2 w-[60px] text-center">#{{ message.id }}</td>
|
||||||
|
<td class="p-2 whitespace-nowrap overflow-hidden overflow-ellipsis">{{ message.sender }}</td>
|
||||||
|
<td class="p-2">{{ message.email }}</td>
|
||||||
|
<td class="flex items-center justify-end gap-2 p-3 z-50">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
class="px-3 py-3 text-red-600 hover:text-red-800"
|
||||||
|
:href="`/dashboard/message/${message.id}/delete`"
|
||||||
|
title="Usuń wiadomość z listy"><FontAwesomeIcon :icon="['fas', 'trash']" /></InertiaLink>
|
||||||
|
</td>
|
||||||
|
</InertiaLink>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<EmptyState v-else :icon="['fas', 'message']">
|
||||||
|
<template #title>Brak wiadomości</template>
|
||||||
|
<template #text>Nie przesłano jeszcze żadnej wiadomości.</template>
|
||||||
|
</EmptyState>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
71
resources/js/Pages/Messages/Show.vue
Normal file
71
resources/js/Pages/Messages/Show.vue
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
message: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const splitMessage = computed(() => props.message.message.split("\n"));
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<InertiaHead title="Szczegóły wiadomości" />
|
||||||
|
<div class="p-4">
|
||||||
|
<header class="flex justify-between items-center pb-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
href="/dashboard/message"
|
||||||
|
class="px-2 text-xl text-gray-700 hover:text-black"
|
||||||
|
title="Wróć do listy wiadomości"><FontAwesomeIcon :icon="['fas', 'caret-left']" /></InertiaLink>
|
||||||
|
<h1 class="text-3xl font-roboto font-light">Szczegóły wiadomości</h1>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-3 sm:gap-2">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
:href="`/dashboard/message/${message.id}/delete`"
|
||||||
|
class="flex items-center gap-2 px-2 py-1 text-red-600 hover:text-white hover:bg-red-600 rounded-md"
|
||||||
|
title="Usuń wiadomość"
|
||||||
|
><FontAwesomeIcon :icon="['fas', 'trash']" /><span class="hidden sm:inline-block">Usuń</span></InertiaLink>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div class="mb-4">
|
||||||
|
<header>
|
||||||
|
<h2 class="text-2xl font-roboto font-light pb-3">Podstawowe informacje</h2>
|
||||||
|
</header>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<div class="text-gray-500 pb-0.5">ID</div>
|
||||||
|
<p class="w-full min-w-full max-w-full px-2.5 py-2 border-b-2 rounded-md bg-white whitespace-nowrap overflow-hidden overflow-ellipsis">{{ message.id }}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-gray-500 pb-0.5">Nadawca</div>
|
||||||
|
<p class="w-full min-w-full max-w-full px-2.5 py-2 border-b-2 rounded-md bg-white">{{ message.sender }}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-gray-500 pb-0.5">E-mail</div>
|
||||||
|
<p class="w-full min-w-full max-w-full px-2.5 py-2 border-b-2 rounded-md bg-white">{{ message.email }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<header>
|
||||||
|
<h2 class="text-2xl font-roboto font-light pb-3">Treść wiadomości</h2>
|
||||||
|
</header>
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
|
<div class="col-span-1 sm:col-span-2">
|
||||||
|
<div class="text-gray-500 pb-0.5">Wiadomość</div>
|
||||||
|
<div class="w-full min-w-full max-w-full px-2.5 py-2 border-b-2 rounded-md bg-white">
|
||||||
|
<p
|
||||||
|
v-for="(messageLine, key) in splitMessage"
|
||||||
|
:key="key"
|
||||||
|
>{{ messageLine }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
37
resources/js/Pages/Notes/ConfirmDelete.vue
Normal file
37
resources/js/Pages/Notes/ConfirmDelete.vue
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<script setup>
|
||||||
|
import { router } from '@inertiajs/vue3';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
note: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
function confirmDelete() {
|
||||||
|
router.delete(`/dashboard/note/${props.note.id}/delete`);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<InertiaHead title="Usuwanie notatki" />
|
||||||
|
<div class="p-4">
|
||||||
|
<header class="pb-4">
|
||||||
|
<h1 class="text-3xl font-roboto font-light">Usuwanie notatki</h1>
|
||||||
|
</header>
|
||||||
|
<div class="max-w-[600px]">
|
||||||
|
<p class="mb-4">Na pewno usunąć notatkę {{ note.title }}?</p>
|
||||||
|
<div class="grid grid-cols-3 gap-2">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
:href="`/dashboard/note/${note.id}`"
|
||||||
|
class="col-span-1 flex justify-center items-center gap-3 w-full px-2 py-1 border-t-4 border-b-4 border-transparent hover:border-b-black"
|
||||||
|
><FontAwesomeIcon :icon="['fas', 'backward']" />Anuluj</InertiaLink>
|
||||||
|
<button
|
||||||
|
@click.prevent="confirmDelete"
|
||||||
|
class="col-span-2 flex justify-center items-center gap-3 w-full px-2 py-1 rounded-md bg-red-600 border-4 border-red-600 text-white text-lg hover:bg-transparent hover:text-red-600"
|
||||||
|
><FontAwesomeIcon :icon="['fas', 'trash']" /><span class="whitespace-nowrap overflow-hidden overflow-ellipsis">Usuń notatkę {{ note.title }}</span></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
49
resources/js/Pages/Notes/Create.vue
Normal file
49
resources/js/Pages/Notes/Create.vue
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<script setup>
|
||||||
|
import { useForm } from '@inertiajs/inertia-vue3';
|
||||||
|
import Input from '../../Share/Components/Input.vue';
|
||||||
|
|
||||||
|
const form = useForm({
|
||||||
|
title: null,
|
||||||
|
note: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
function createNote() {
|
||||||
|
form.post('/dashboard/note');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<InertiaHead title="Nowe dane do CV" />
|
||||||
|
<div class="p-4">
|
||||||
|
<header class="pb-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
href="/dashboard/note"
|
||||||
|
class="px-2 text-xl text-gray-700 hover:text-black"
|
||||||
|
title="Wróć do listy notatek"><FontAwesomeIcon :icon="['fas', 'caret-left']" /></InertiaLink>
|
||||||
|
<h1 class="text-3xl font-roboto font-light">Nowe dane do CV</h1>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div>
|
||||||
|
<form class="flex flex-col gap-4" @submit.prevent="createNote">
|
||||||
|
<Input
|
||||||
|
id="title"
|
||||||
|
label="Tytuł notatki"
|
||||||
|
placeholder="np. Witaj świecie!"
|
||||||
|
v-model="form.title"
|
||||||
|
:error="form.errors.title"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="note"
|
||||||
|
type="textarea"
|
||||||
|
label="Treść notatki"
|
||||||
|
placeholder="Treść"
|
||||||
|
v-model="form.note"
|
||||||
|
:error="form.errors.note"
|
||||||
|
/>
|
||||||
|
<button class="px-0.5 py-1 rounded-lg bg-[#436da7] border-4 border-[#436da7] text-white text-lg hover:bg-transparent hover:text-[#436da7]">Utwórz notatkę</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
69
resources/js/Pages/Notes/Edit.vue
Normal file
69
resources/js/Pages/Notes/Edit.vue
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
<script setup>
|
||||||
|
import { useForm } from '@inertiajs/inertia-vue3';
|
||||||
|
import Input from '../../Share/Components/Input.vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
note: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const form = useForm({
|
||||||
|
title: props.note.title,
|
||||||
|
note: props.note.note,
|
||||||
|
});
|
||||||
|
|
||||||
|
function updateNote() {
|
||||||
|
form.put(`/dashboard/note/${props.note.id}`);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<InertiaHead title="Edycja notatki" />
|
||||||
|
<div class="p-4">
|
||||||
|
<header class="flex items-center justify-between pb-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
:href="`/dashboard/note/${note.id}`"
|
||||||
|
class="px-2 text-xl text-gray-700 hover:text-black"
|
||||||
|
title="Wróć do listy notatek"><FontAwesomeIcon :icon="['fas', 'caret-left']" /></InertiaLink>
|
||||||
|
<h1 class="text-3xl font-roboto font-light">Edycja notatki</h1>
|
||||||
|
</div>
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
:href="`/dashboard/note/${note.id}/delete`"
|
||||||
|
class="flex items-center gap-2 px-2 py-1 text-red-600 hover:text-white hover:bg-red-600 rounded-md"
|
||||||
|
title="Usuń notatkę"
|
||||||
|
><FontAwesomeIcon :icon="['fas', 'trash']" />Usuń</InertiaLink>
|
||||||
|
</header>
|
||||||
|
<div>
|
||||||
|
<form class="flex flex-col gap-4" @submit.prevent="updateNote">
|
||||||
|
<Input
|
||||||
|
id="title"
|
||||||
|
label="Tytuł notatki"
|
||||||
|
placeholder="np. Witaj świecie!"
|
||||||
|
v-model="form.title"
|
||||||
|
:error="form.errors.title"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="note"
|
||||||
|
type="textarea"
|
||||||
|
label="Treść notatki"
|
||||||
|
placeholder="Treść"
|
||||||
|
v-model="form.note"
|
||||||
|
:error="form.errors.note"
|
||||||
|
/>
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-3 sm:gap-2 items-center">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
:href="`/dashboard/note/${note.id}`"
|
||||||
|
class="col-span-1 flex justify-center items-center gap-3 w-full px-2 py-1 border-t-4 border-b-4 border-transparent hover:border-b-black"
|
||||||
|
><FontAwesomeIcon :icon="['fas', 'backward']" />Anuluj</InertiaLink>
|
||||||
|
<button class="col-span-1 md:col-span-2 px-0.5 py-1 rounded-lg bg-[#436da7] border-4 border-[#436da7] text-white text-lg hover:bg-transparent hover:text-[#436da7]">Edytuj notatkę</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
57
resources/js/Pages/Notes/Index.vue
Normal file
57
resources/js/Pages/Notes/Index.vue
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<script setup>
|
||||||
|
import EmptyState from '@/Share/Components/EmptyState.vue';
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
notes: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<InertiaHead title="Lista notatek" />
|
||||||
|
<div class="p-4">
|
||||||
|
<header class="flex justify-between items-center pb-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
href="/dashboard"
|
||||||
|
class="px-2 text-xl text-gray-700 hover:text-black"
|
||||||
|
title="Wróc do dashboard"><FontAwesomeIcon :icon="['fas', 'caret-left']" /></InertiaLink>
|
||||||
|
<h1 class="text-3xl font-roboto font-light">Lista notatek</h1>
|
||||||
|
</div>
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
href="/dashboard/note/create"
|
||||||
|
class="bg-blue-400 hover:bg-blue-500 text-white px-2.5 py-1 rounded-full"
|
||||||
|
title="Dodaj nowe dane dla CV"
|
||||||
|
><FontAwesomeIcon :icon="['fas', 'plus']" /></InertiaLink>
|
||||||
|
</header>
|
||||||
|
<ul v-if="notes.data.length" class="flex flex-col gap-2">
|
||||||
|
<li
|
||||||
|
v-for="(note, key) in notes.data"
|
||||||
|
:key="key"
|
||||||
|
class="flex items-center justify-between px-3 py-2 bg-white hover:bg-neutral-200"
|
||||||
|
>
|
||||||
|
<InertiaLink :href="`/dashboard/note/${note.id}`">{{ note.title }}</InertiaLink>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
class="px-2 py-1 text-lime-600 hover:text-lime-800 border-t-2 border-b-2 border-transparent hover:border-b-lime-600"
|
||||||
|
:href="`/dashboard/note/${note.id}/edit`"
|
||||||
|
title="Edytuj notatkę"><FontAwesomeIcon :icon="['fas', 'pen-to-square']" /></InertiaLink>
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
class="px-2 py-1 text-red-600 hover:text-red-800"
|
||||||
|
:href="`/dashboard/note/${note.id}/delete`"
|
||||||
|
title="Usuń notatkę z listy"><FontAwesomeIcon :icon="['fas', 'trash']" /></InertiaLink>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<EmptyState v-else>
|
||||||
|
<template #title>Nie znaleziono notatek</template>
|
||||||
|
<template #text>Nie dodano jeszcze notatek do listy.</template>
|
||||||
|
</EmptyState>
|
||||||
|
</div>
|
||||||
|
</template>
|
64
resources/js/Pages/Notes/Show.vue
Normal file
64
resources/js/Pages/Notes/Show.vue
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
note: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const noteLines = computed(() => props.note.note.split("\n"));
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<InertiaHead title="Szczegóły notatki" />
|
||||||
|
<div class="p-4">
|
||||||
|
<header class="flex justify-between items-center pb-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
href="/dashboard/note"
|
||||||
|
class="px-2 text-xl text-gray-700 hover:text-black"
|
||||||
|
title="Wróć do listy notatek"><FontAwesomeIcon :icon="['fas', 'caret-left']" /></InertiaLink>
|
||||||
|
<h1 class="text-3xl font-roboto font-light">Szczegóły notatki</h1>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-3 sm:gap-2">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
:href="`/dashboard/note/${note.id}/edit`"
|
||||||
|
class="flex items-center gap-2 px-2 py-1 text-lime-600 hover:text-white hover:bg-lime-600 rounded-md"
|
||||||
|
title="Edytuj notatkę"
|
||||||
|
><FontAwesomeIcon :icon="['fas', 'pen-to-square']" /><span class="hidden sm:inline-block">Edytuj</span></InertiaLink>
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
:href="`/dashboard/note/${note.id}/delete`"
|
||||||
|
class="flex items-center gap-2 px-2 py-1 text-red-600 hover:text-white hover:bg-red-600 rounded-md"
|
||||||
|
title="Usuń notatkę"
|
||||||
|
><FontAwesomeIcon :icon="['fas', 'trash']" /><span class="hidden sm:inline-block">Usuń</span></InertiaLink>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div class="mb-4">
|
||||||
|
<header>
|
||||||
|
<h2 class="text-2xl font-roboto font-light pb-3">Podstawowe informacje</h2>
|
||||||
|
</header>
|
||||||
|
<div class="flex flex-col gap-4">
|
||||||
|
<div>
|
||||||
|
<div class="text-gray-500 pb-0.5">Tytuł</div>
|
||||||
|
<p
|
||||||
|
class="w-full min-w-full max-w-full px-2.5 py-2 border-b-2 rounded-md bg-white whitespace-nowrap overflow-hidden overflow-ellipsis"
|
||||||
|
>{{ note.title }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="md:col-span-2">
|
||||||
|
<div class="text-gray-500 pb-0.5">Notatka</div>
|
||||||
|
<div class="w-full min-w-full max-w-full px-2.5 py-2 border-b-2 rounded-md bg-white">
|
||||||
|
<p
|
||||||
|
v-for="(noteLine, key) in noteLines"
|
||||||
|
:key="key"
|
||||||
|
>{{ noteLine }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
37
resources/js/Pages/Projects/ConfirmDelete.vue
Normal file
37
resources/js/Pages/Projects/ConfirmDelete.vue
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<script setup>
|
||||||
|
import { router } from '@inertiajs/vue3';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
project: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
function confirmDelete() {
|
||||||
|
router.delete(`/dashboard/project/${props.project.id}/delete`);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<InertiaHead title="Nowy projekt" />
|
||||||
|
<div class="p-4">
|
||||||
|
<header class="pb-4">
|
||||||
|
<h1 class="text-3xl font-roboto font-light">Usuwanie projektu</h1>
|
||||||
|
</header>
|
||||||
|
<div class="max-w-[600px]">
|
||||||
|
<p class="mb-4">Na pewno usunąć projekt o nazwie {{ project.title }}?</p>
|
||||||
|
<div class="grid grid-cols-3 gap-2">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
href="/dashboard"
|
||||||
|
class="col-span-1 flex justify-center items-center gap-3 w-full px-2 py-1 border-t-4 border-b-4 border-transparent hover:border-b-black"
|
||||||
|
><FontAwesomeIcon :icon="['fas', 'backward']" />Anuluj</InertiaLink>
|
||||||
|
<button
|
||||||
|
@click.prevent="confirmDelete"
|
||||||
|
class="col-span-2 flex justify-center items-center gap-3 w-full px-2 py-1 rounded-md bg-red-600 border-4 border-red-600 text-white text-lg hover:bg-transparent hover:text-red-600"
|
||||||
|
><FontAwesomeIcon :icon="['fas', 'trash']" />Usuń projekt {{ project.title }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
160
resources/js/Pages/Projects/Create.vue
Normal file
160
resources/js/Pages/Projects/Create.vue
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
<script setup>
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import { useForm } from '@inertiajs/inertia-vue3';
|
||||||
|
import Input from '../../Share/Components/Input.vue';
|
||||||
|
|
||||||
|
const categories = ref([]);
|
||||||
|
|
||||||
|
const categoryToString = computed({
|
||||||
|
get: () => categories.value.join(', '),
|
||||||
|
set: (val) => {
|
||||||
|
val = val.replace(', ', ',').replace(' , ', ',').replace(' ,', ',');
|
||||||
|
val = val.split(',');
|
||||||
|
val.forEach((element, key) => {
|
||||||
|
element = element.trim();
|
||||||
|
val[key] = slug(element);
|
||||||
|
});
|
||||||
|
categories.value = val;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const form = useForm({
|
||||||
|
title: null,
|
||||||
|
author: null,
|
||||||
|
categories: categoryToString,
|
||||||
|
release_date: null,
|
||||||
|
update_date: null,
|
||||||
|
image_small: null,
|
||||||
|
image_medium: null,
|
||||||
|
image_large: null,
|
||||||
|
project_url: null,
|
||||||
|
project_version: null,
|
||||||
|
description: null,
|
||||||
|
visible: Boolean(false),
|
||||||
|
});
|
||||||
|
|
||||||
|
function createProject() {
|
||||||
|
form.post('/dashboard/project');
|
||||||
|
}
|
||||||
|
|
||||||
|
function slug(str) {
|
||||||
|
str = str.replace(/^\s+|\s+$/g, ''); // trim
|
||||||
|
str = str.toLowerCase();
|
||||||
|
|
||||||
|
// remove accents, swap ñ for n, etc
|
||||||
|
var from = "ãàáäâẽèéëêìíïîõòóöôùúüûñç·/_,:;";
|
||||||
|
var to = "aaaaaeeeeeiiiiooooouuuunc------";
|
||||||
|
for (var i = 0, l = from.length; i < l; i++) {
|
||||||
|
str = str.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
str = str.replace(/[^a-z0-9 -]/g, '') // remove invalid chars
|
||||||
|
.replace(/\s+/g, '-') // collapse whitespace and replace by -
|
||||||
|
.replace(/-+/g, '-'); // collapse dashes
|
||||||
|
|
||||||
|
return str;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<InertiaHead title="Nowy projekt" />
|
||||||
|
<div class="p-4">
|
||||||
|
<header class="pb-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
href="/dashboard"
|
||||||
|
class="px-2 text-xl text-gray-700 hover:text-black"
|
||||||
|
title="Wróc do dashboard"><FontAwesomeIcon :icon="['fas', 'caret-left']" /></InertiaLink>
|
||||||
|
<h1 class="text-3xl font-roboto font-light">Nowy projekt</h1>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div>
|
||||||
|
<form class="flex flex-col gap-4" @submit.prevent="createProject">
|
||||||
|
<Input
|
||||||
|
id="title"
|
||||||
|
label="Tytuł"
|
||||||
|
placeholder="Nazwa projektu"
|
||||||
|
v-model="form.title"
|
||||||
|
:error="form.errors.title"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="author"
|
||||||
|
label="Autor"
|
||||||
|
placeholder="Imię i nazwisko"
|
||||||
|
v-model="form.author"
|
||||||
|
:error="form.errors.author"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="categories"
|
||||||
|
label="Kategorie"
|
||||||
|
placeholder="Kategorie projektu"
|
||||||
|
v-model="form.categories"
|
||||||
|
:error="form.errors.categories"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="release_date"
|
||||||
|
label="Data pierwszego wydania"
|
||||||
|
type="date"
|
||||||
|
v-model="form.release_date"
|
||||||
|
:error="form.errors.release_date"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="update_date"
|
||||||
|
label="Data aktualizacji"
|
||||||
|
type="date"
|
||||||
|
v-model="form.update_date"
|
||||||
|
:error="form.errors.update_date"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="image_small"
|
||||||
|
label="Zdjęcie projekty - małe"
|
||||||
|
v-model="form.image_small"
|
||||||
|
:error="form.errors.image_small"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="image_medium"
|
||||||
|
label="Zdjęcie projekty - średnie"
|
||||||
|
v-model="form.image_medium"
|
||||||
|
:error="form.errors.image_medium"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="image_large"
|
||||||
|
label="Zdjęcie projekty - duże"
|
||||||
|
v-model="form.image_large"
|
||||||
|
:error="form.errors.image_large"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="project_url"
|
||||||
|
label="Adres projektu"
|
||||||
|
placeholder="Adres www strony projektu"
|
||||||
|
v-model="form.project_url"
|
||||||
|
:error="form.errors.project_url"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="project_version"
|
||||||
|
label="Wersja projektu"
|
||||||
|
placeholder="v1.0.0"
|
||||||
|
v-model="form.project_version"
|
||||||
|
:error="form.errors.project_version"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="description"
|
||||||
|
label="Opis"
|
||||||
|
type="textarea"
|
||||||
|
placeholder="Ładny opis"
|
||||||
|
v-model="form.description"
|
||||||
|
:error="form.errors.description"
|
||||||
|
textareaHeight="200px"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="visible"
|
||||||
|
label="Widoczny"
|
||||||
|
type="checkbox"
|
||||||
|
v-model="form.visible"
|
||||||
|
/>
|
||||||
|
<button class="px-0.5 py-1 rounded-lg bg-[#436da7] border-4 border-[#436da7] text-white text-lg hover:bg-transparent hover:text-[#436da7]">Dodaj projekt</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
173
resources/js/Pages/Projects/Edit.vue
Normal file
173
resources/js/Pages/Projects/Edit.vue
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
<script setup>
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import { useForm } from '@inertiajs/inertia-vue3';
|
||||||
|
import Input from '../../Share/Components/Input.vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
project: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const categories = ref(props.project?.categories ?? []);
|
||||||
|
|
||||||
|
const categoryToString = computed({
|
||||||
|
get: () => categories.value.join(', '),
|
||||||
|
set: (val) => {
|
||||||
|
val = val.replace(', ', ',').replace(' , ', ',').replace(' ,', ',');
|
||||||
|
val = val.split(',');
|
||||||
|
val.forEach((element, key) => {
|
||||||
|
element = element.trim();
|
||||||
|
val[key] = slug(element);
|
||||||
|
});
|
||||||
|
categories.value = val;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const form = useForm({
|
||||||
|
title: props.project.title,
|
||||||
|
author: props.project.author,
|
||||||
|
categories: categoryToString,
|
||||||
|
release_date: props.project.release_date,
|
||||||
|
update_date: props.project.update_date,
|
||||||
|
image_small: props.project?.images['small'] ?? '',
|
||||||
|
image_medium: props.project?.images['medium'] ?? '',
|
||||||
|
image_large: props.project?.images['large'] ?? '',
|
||||||
|
project_url: props.project.project_url,
|
||||||
|
project_version: props.project.project_version,
|
||||||
|
description: props.project.description,
|
||||||
|
visible: Boolean(props.project.visible),
|
||||||
|
});
|
||||||
|
|
||||||
|
function updateProject() {
|
||||||
|
form.put(`/dashboard/project/${props.project.id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function slug(str) {
|
||||||
|
str = str.replace(/^\s+|\s+$/g, ''); // trim
|
||||||
|
str = str.toLowerCase();
|
||||||
|
|
||||||
|
// remove accents, swap ñ for n, etc
|
||||||
|
var from = "ãàáäâẽèéëêìíïîõòóöôùúüûñç·/_,:;";
|
||||||
|
var to = "aaaaaeeeeeiiiiooooouuuunc------";
|
||||||
|
for (var i = 0, l = from.length; i < l; i++) {
|
||||||
|
str = str.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
str = str.replace(/[^a-z0-9 -]/g, '') // remove invalid chars
|
||||||
|
.replace(/\s+/g, '-') // collapse whitespace and replace by -
|
||||||
|
.replace(/-+/g, '-'); // collapse dashes
|
||||||
|
|
||||||
|
return str;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<InertiaHead title="Nowy projekt" />
|
||||||
|
<div class="p-4">
|
||||||
|
<header class="flex items-center justify-between pb-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
href="/dashboard"
|
||||||
|
class="px-2 text-xl text-gray-700 hover:text-black"
|
||||||
|
title="Wróc do dashboard"><FontAwesomeIcon :icon="['fas', 'caret-left']" /></InertiaLink>
|
||||||
|
<h1 class="text-3xl font-roboto font-light">Edytuj {{ project.title }}</h1>
|
||||||
|
</div>
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
:href="`/dashboard/project/${project.id}/delete`"
|
||||||
|
class="flex items-center gap-2 px-2 py-1 text-red-600 hover:text-white hover:bg-red-600 rounded-md"
|
||||||
|
title="Usuń projekt"
|
||||||
|
><FontAwesomeIcon :icon="['fas', 'trash']" />Usuń</InertiaLink>
|
||||||
|
</header>
|
||||||
|
<div>
|
||||||
|
<form class="flex flex-col gap-4" @submit.prevent="updateProject">
|
||||||
|
<Input
|
||||||
|
id="title"
|
||||||
|
label="Tytuł"
|
||||||
|
placeholder="Nazwa projektu"
|
||||||
|
v-model="form.title"
|
||||||
|
:error="form.errors.title"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="author"
|
||||||
|
label="Autor"
|
||||||
|
placeholder="Imię i nazwisko"
|
||||||
|
v-model="form.author"
|
||||||
|
:error="form.errors.author"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="categories"
|
||||||
|
label="Kategorie"
|
||||||
|
placeholder="Kategorie projektu"
|
||||||
|
v-model="form.categories"
|
||||||
|
:error="form.errors.categories"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="release_date"
|
||||||
|
label="Data pierwszego wydania"
|
||||||
|
type="date"
|
||||||
|
v-model="form.release_date"
|
||||||
|
:error="form.errors.release_date"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="update_date"
|
||||||
|
label="Data aktualizacji"
|
||||||
|
type="date"
|
||||||
|
v-model="form.update_date"
|
||||||
|
:error="form.errors.update_date"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="image_small"
|
||||||
|
label="Zdjęcie projekty - małe"
|
||||||
|
v-model="form.image_small"
|
||||||
|
:error="form.errors.image_small"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="image_medium"
|
||||||
|
label="Zdjęcie projekty - średnie"
|
||||||
|
v-model="form.image_medium"
|
||||||
|
:error="form.errors.image_medium"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="image_large"
|
||||||
|
label="Zdjęcie projekty - duże"
|
||||||
|
v-model="form.image_large"
|
||||||
|
:error="form.errors.image_large"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="project_url"
|
||||||
|
label="Adres projektu"
|
||||||
|
placeholder="Adres www strony projektu"
|
||||||
|
v-model="form.project_url"
|
||||||
|
:error="form.errors.project_url"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="project_version"
|
||||||
|
label="Wersja projektu"
|
||||||
|
placeholder="v1.0.0"
|
||||||
|
v-model="form.project_version"
|
||||||
|
:error="form.errors.project_version"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="description"
|
||||||
|
label="Opis"
|
||||||
|
type="textarea"
|
||||||
|
placeholder="Ładny opis"
|
||||||
|
v-model="form.description"
|
||||||
|
:error="form.errors.description"
|
||||||
|
textareaHeight="200px"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="visible"
|
||||||
|
label="Widoczny"
|
||||||
|
type="checkbox"
|
||||||
|
v-model="form.visible"
|
||||||
|
/>
|
||||||
|
<button class="px-0.5 py-1 rounded-lg bg-[#436da7] border-4 border-[#436da7] text-white text-lg hover:bg-transparent hover:text-[#436da7]">Aktualizuj projekt</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
48
resources/js/Share/CategoriesList.vue
Normal file
48
resources/js/Share/CategoriesList.vue
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<script setup>
|
||||||
|
import EmptyState from '@/Share/Components/EmptyState.vue';
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
categories: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section class="bg-gray-100 rounded-md p-4">
|
||||||
|
<header class="flex justify-between items-center pb-4">
|
||||||
|
<h2 class="text-2xl font-roboto font-light">Kategorie</h2>
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
href="/dashboard/category/create"
|
||||||
|
class="bg-blue-400 hover:bg-blue-500 text-white px-2.5 py-1 rounded-full"><FontAwesomeIcon :icon="['fas', 'plus']" /></InertiaLink>
|
||||||
|
</header>
|
||||||
|
<ul v-if="categories.length" class="flex flex-col gap-2">
|
||||||
|
<li
|
||||||
|
v-for="(category, key) in categories"
|
||||||
|
:key="key"
|
||||||
|
class="flex items-center justify-between px-3 py-2 bg-white hover:bg-neutral-200"
|
||||||
|
>
|
||||||
|
<InertiaLink :href="`/dashboard/category/${category.id}`">{{ category.name }}</InertiaLink>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
class="px-1 py-0.5 text-lime-600 hover:text-lime-800 border-t-2 border-b-2 border-transparent hover:border-b-lime-600"
|
||||||
|
:href="`/dashboard/category/${category.id}`"
|
||||||
|
title="Edytuj kategorię"><FontAwesomeIcon :icon="['fas', 'pen-to-square']" /></InertiaLink>
|
||||||
|
<InertiaLink
|
||||||
|
v-if="!category.default"
|
||||||
|
as="button"
|
||||||
|
class="px-1 py-0.5 text-red-600 hover:text-red-800"
|
||||||
|
:href="`/dashboard/category/${category.id}/delete`"
|
||||||
|
title="Usuń kategorię z listy"><FontAwesomeIcon :icon="['fas', 'trash']" /></InertiaLink>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<EmptyState v-else :icon="['fas', 'list']">
|
||||||
|
<template #title>Brak kategorii</template>
|
||||||
|
<template #text>Nie dodano jeszcze żadnej kategorii.</template>
|
||||||
|
</EmptyState>
|
||||||
|
</section>
|
||||||
|
</template>
|
31
resources/js/Share/Components/EmptyState.vue
Normal file
31
resources/js/Share/Components/EmptyState.vue
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<script setup>
|
||||||
|
defineProps({
|
||||||
|
icon: {
|
||||||
|
type: Array,
|
||||||
|
default: ['far', 'folder-open'],
|
||||||
|
},
|
||||||
|
showDescription: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="text-center my-5 text-gray-500">
|
||||||
|
<slot name="head">
|
||||||
|
<FontAwesomeIcon :icon="icon" class="mx-auto w-12 h-12" />
|
||||||
|
</slot>
|
||||||
|
<h3 class="mt-2 text-sm font-medium">
|
||||||
|
<slot name="title">Brak danych</slot>
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
v-if="showDescription"
|
||||||
|
class="text-sm"
|
||||||
|
>
|
||||||
|
<slot name="text">
|
||||||
|
Nie znaleziono danych.
|
||||||
|
</slot>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
53
resources/js/Share/Components/Input.vue
Normal file
53
resources/js/Share/Components/Input.vue
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<script setup>
|
||||||
|
defineProps({
|
||||||
|
modelValue: [String, Boolean, Number],
|
||||||
|
id: String,
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'text',
|
||||||
|
},
|
||||||
|
label: String,
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
type: String,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
textareaHeight: {
|
||||||
|
type: String,
|
||||||
|
default: null,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
defineEmits(['update:model-value']);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div :class="['flex w-full', (type === 'checkbox' ? 'flex-row gap-2 items-center bg-gray-200 px-2 py-2 rounded-md' : 'flex-col gap-1')]">
|
||||||
|
<label v-if="id"
|
||||||
|
:for="id"
|
||||||
|
class="text-gray-500">{{ label }}</label>
|
||||||
|
<textarea v-if="type === 'textarea'"
|
||||||
|
:id="id"
|
||||||
|
:class="['w-full min-w-full max-w-full h-[200px] min-h-[200px] px-2.5 py-2 border-b-2 rounded-md', error ? 'border-red-300 focus:border-red-400 hover:border-red-500 outline-none text-red-900 placeholder-red-400' : 'border-neutral-300 focus:border-neutral-400 hover:border-neutral-500 outline-none text-gray-900 placeholder-gray-400']"
|
||||||
|
:value="modelValue"
|
||||||
|
@input="$emit('update:model-value', $event.target.value)"
|
||||||
|
:placeholder="placeholder"></textarea>
|
||||||
|
<input v-else-if="type === 'checkbox'"
|
||||||
|
:id="id"
|
||||||
|
:checked="modelValue"
|
||||||
|
@input="$emit('update:model-value', $event.target.checked)"
|
||||||
|
:true-value="true"
|
||||||
|
:false-value="false"
|
||||||
|
type="checkbox" />
|
||||||
|
<input v-else
|
||||||
|
:id="id"
|
||||||
|
:class="['w-full px-2.5 py-2 border-b-2 rounded-md', error ? 'border-red-300 focus:border-red-400 hover:border-red-500 outline-none text-red-900 placeholder-red-400' : 'border-neutral-300 focus:border-neutral-400 hover:border-neutral-500 outline-none text-gray-900 placeholder-gray-400']"
|
||||||
|
:type="type"
|
||||||
|
:value="modelValue"
|
||||||
|
@input="$emit('update:model-value', $event.target.value)"
|
||||||
|
:placeholder="placeholder" />
|
||||||
|
<span class="text-red-400" v-if="error">{{ error }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
@@ -1,7 +1,50 @@
|
|||||||
<template>
|
|
||||||
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
defineProps({
|
||||||
|
responseMessages: {
|
||||||
|
type: Object,
|
||||||
|
default: {},
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="css" scoped>
|
||||||
|
.header {
|
||||||
|
background: linear-gradient(237.74deg,#1199a5,#436da7 83%);
|
||||||
|
}
|
||||||
|
.logo-green {
|
||||||
|
color: rgb(162, 207, 0);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<header class="header">
|
||||||
|
<div class="flex gap-5 items-center justify-start max-w-screen-lg mx-auto font-thasadith">
|
||||||
|
<InertiaLink href="/dashboard">
|
||||||
|
<div
|
||||||
|
class="bg-white text-gray-800 pl-10 pr-5 py-2.5 text-4xl"
|
||||||
|
>Kamil<span class="logo-green">Craft</span></div>
|
||||||
|
</InertiaLink>
|
||||||
|
<nav>
|
||||||
|
<ul class="flex gap-3 items-center font-bold">
|
||||||
|
<li><InertiaLink class="text-white active:text-kamilcraft-green hover:text-black hover:underline" href="/dashboard/cv">CV</InertiaLink></li>
|
||||||
|
<li><InertiaLink class="text-white active:text-kamilcraft-green hover:text-black hover:underline" href="/dashboard/message">Msg</InertiaLink></li>
|
||||||
|
<li><InertiaLink class="text-white active:text-kamilcraft-green hover:text-black hover:underline" href="/dashboard/note">Notes</InertiaLink></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div v-if="responseMessages?.info" class="max-w-screen-lg mx-2 lg:mx-auto mt-2 px-2 py-3 rounded-md bg-yellow-100 text-yellow-600 text-center">
|
||||||
|
{{ responseMessages.info }}
|
||||||
|
</div>
|
||||||
|
<div v-if="responseMessages?.error" class="max-w-screen-lg mx-2 lg:mx-auto mt-2 px-2 py-3 rounded-md bg-red-100 text-red-600 text-center">
|
||||||
|
{{ responseMessages.error }}
|
||||||
|
</div>
|
||||||
|
<div v-if="responseMessages?.success" class="max-w-screen-lg mx-2 lg:mx-auto mt-2 px-2 py-3 rounded-md bg-green-100 text-green-600 text-center">
|
||||||
|
{{ responseMessages.success }}
|
||||||
|
</div>
|
||||||
|
<main class="max-w-screen-lg mx-2 lg:mx-auto mt-2 rounded-md bg-gray-50">
|
||||||
|
<slot />
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
30
resources/js/Share/Layout/Guest.vue
Normal file
30
resources/js/Share/Layout/Guest.vue
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<script setup>
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="css" scoped>
|
||||||
|
.header {
|
||||||
|
@apply min-h-[220px];
|
||||||
|
background: linear-gradient(237.74deg,#1199a5,#436da7 83%);
|
||||||
|
}
|
||||||
|
.logo-green {
|
||||||
|
color: rgb(162, 207, 0);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<header class="header">
|
||||||
|
<div class="flex gap-5 items-center justify-between md:justify-start max-w-screen-xl mx-auto font-thasadith">
|
||||||
|
<InertiaLink href="/dashboard">
|
||||||
|
<div
|
||||||
|
class="bg-white text-gray-800 pl-10 pr-5 py-2.5 text-4xl"
|
||||||
|
>Kamil<span class="logo-green">Craft</span></div>
|
||||||
|
</InertiaLink>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main class="-my-24 px-2 sm:px-0">
|
||||||
|
<slot />
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</template>
|
48
resources/js/Share/ProjectsList.vue
Normal file
48
resources/js/Share/ProjectsList.vue
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<script setup>
|
||||||
|
import EmptyState from '@/Share/Components/EmptyState.vue';
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
projects: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section class="bg-gray-100 rounded-md p-4">
|
||||||
|
<header class="flex justify-between items-center pb-4">
|
||||||
|
<h2 class="text-2xl font-roboto font-light">Projekty</h2>
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
href="/dashboard/project/create"
|
||||||
|
class="bg-blue-400 hover:bg-blue-500 text-white px-2.5 py-1 rounded-full"
|
||||||
|
><FontAwesomeIcon :icon="['fas', 'plus']" /></InertiaLink>
|
||||||
|
</header>
|
||||||
|
<ul v-if="projects.length" class="flex flex-col gap-2">
|
||||||
|
<li
|
||||||
|
v-for="(project, key) in projects"
|
||||||
|
:key="key"
|
||||||
|
class="flex items-center justify-between px-3 py-2 bg-white hover:bg-neutral-200"
|
||||||
|
>
|
||||||
|
<InertiaLink :href="`/dashboard/project/${project.id}`">{{ project.title }}</InertiaLink>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
class="px-2 py-1 text-lime-600 hover:text-lime-800 border-t-2 border-b-2 border-transparent hover:border-b-lime-600"
|
||||||
|
:href="`/dashboard/project/${project.id}`"
|
||||||
|
title="Edytuj projekt"><FontAwesomeIcon :icon="['fas', 'pen-to-square']" /></InertiaLink>
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
class="px-2 py-1 text-red-600 hover:text-red-800"
|
||||||
|
:href="`/dashboard/project/${project.id}/delete`"
|
||||||
|
title="Usuń projekt z listy"><FontAwesomeIcon :icon="['fas', 'trash']" /></InertiaLink>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<EmptyState v-else :icon="['fas', 'bars-progress']">
|
||||||
|
<template #title>Brak projektów</template>
|
||||||
|
<template #text>Nie dodano jeszcze żadnego projektu.</template>
|
||||||
|
</EmptyState>
|
||||||
|
</section>
|
||||||
|
</template>
|
19
resources/js/app.js
vendored
19
resources/js/app.js
vendored
@@ -1,9 +1,22 @@
|
|||||||
import './bootstrap';
|
import './bootstrap';
|
||||||
|
|
||||||
|
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
|
||||||
|
|
||||||
import { createApp, h } from 'vue';
|
import { createApp, h } from 'vue';
|
||||||
import { createInertiaApp, Head, Link } from '@inertiajs/inertia-vue3';
|
import { createInertiaApp, Head, Link } from '@inertiajs/inertia-vue3';
|
||||||
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
|
|
||||||
|
import { library } from '@fortawesome/fontawesome-svg-core';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
|
||||||
|
import { fas } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { far } from '@fortawesome/free-regular-svg-icons';
|
||||||
|
import { fab } from '@fortawesome/free-brands-svg-icons';
|
||||||
|
|
||||||
|
library.add(fas);
|
||||||
|
library.add(far);
|
||||||
|
library.add(fab);
|
||||||
|
|
||||||
|
import './css/app.css';
|
||||||
import App from '@/Share/Layout/App.vue';
|
import App from '@/Share/Layout/App.vue';
|
||||||
import '../css/app.css';
|
|
||||||
|
|
||||||
createInertiaApp({
|
createInertiaApp({
|
||||||
resolve: async (name) => {
|
resolve: async (name) => {
|
||||||
@@ -23,6 +36,8 @@ createInertiaApp({
|
|||||||
.use(plugin)
|
.use(plugin)
|
||||||
.component('InertiaLink', Link)
|
.component('InertiaLink', Link)
|
||||||
.component('InertiaHead', Head)
|
.component('InertiaHead', Head)
|
||||||
|
.component('FontAwesomeIcon', FontAwesomeIcon)
|
||||||
.mount(el)
|
.mount(el)
|
||||||
},
|
},
|
||||||
|
title: title => `${title} | KamilCraft API`
|
||||||
});
|
});
|
||||||
|
6
resources/js/css/app.css
vendored
6
resources/js/css/app.css
vendored
@@ -1,3 +1,9 @@
|
|||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
:root {
|
||||||
|
--color-logo-green: 162, 207, 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -3,6 +3,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@100;400;700&display=swap" rel="stylesheet">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Thasadith&display=swap" rel="stylesheet">
|
||||||
@vite('resources/js/app.js')
|
@vite('resources/js/app.js')
|
||||||
@inertiaHead
|
@inertiaHead
|
||||||
</head>
|
</head>
|
||||||
|
@@ -17,3 +17,7 @@ Route::get('projects', 'ProjectController@index');
|
|||||||
Route::prefix('project')->group(function() {
|
Route::prefix('project')->group(function() {
|
||||||
Route::get('{project}', 'ProjectController@show');
|
Route::get('{project}', 'ProjectController@show');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Route::get('cv/{cv}', 'CVController@show');
|
||||||
|
|
||||||
|
Route::post('message', 'MessageController@store');
|
||||||
|
@@ -5,9 +5,61 @@ declare(strict_types=1);
|
|||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
Route::name('admin.')->group(function () {
|
Route::name('admin.')->group(function () {
|
||||||
Route::namespace('Dashboard')->middleware('auth')->group(function () {
|
Route::namespace('Dashboard')->middleware('auth')->group(function (): void {
|
||||||
Route::get('', 'AdminPanelController')->name('home');
|
Route::get('', 'AdminPanelController')->name('home');
|
||||||
Route::name('category.')->prefix('category')->group(function () {
|
|
||||||
|
Route::name('note.')->prefix('note')->group(function (): void {
|
||||||
|
Route::get('', 'NoteController@index')
|
||||||
|
->name('index');
|
||||||
|
Route::get('create', 'NoteController@create')
|
||||||
|
->name('create');
|
||||||
|
Route::post('', 'NoteController@store')
|
||||||
|
->name('store');
|
||||||
|
Route::get('{note}', 'NoteController@show')
|
||||||
|
->name('show');
|
||||||
|
Route::get('{note}/edit', 'NoteController@edit')
|
||||||
|
->name('edit');
|
||||||
|
Route::put('{note}', 'NoteController@update')
|
||||||
|
->name('update');
|
||||||
|
Route::get('{note}/delete', 'NoteController@delete')
|
||||||
|
->name('delete');
|
||||||
|
Route::delete('{note}/delete', 'NoteController@destroy')
|
||||||
|
->name('destroy');
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::name('message.')->prefix('message')->group(function (): void {
|
||||||
|
Route::get('', 'MessageController@index')
|
||||||
|
->name('index');
|
||||||
|
Route::get('{message}', 'MessageController@show')
|
||||||
|
->name('show');
|
||||||
|
Route::get('{message}/delete', 'MessageController@delete')
|
||||||
|
->name('delete');
|
||||||
|
Route::delete('{message}/delete', 'MessageController@destroy')
|
||||||
|
->name('destroy');
|
||||||
|
});
|
||||||
|
Route::name('cv.')->prefix('cv')->group(function (): void {
|
||||||
|
Route::get('', 'CVController@index')
|
||||||
|
->name('index');
|
||||||
|
Route::get('create', 'CVController@create')
|
||||||
|
->name('create');
|
||||||
|
Route::post('', 'CVController@store')
|
||||||
|
->name('store');
|
||||||
|
Route::get('{cv}', 'CVController@show')
|
||||||
|
->name('show');
|
||||||
|
Route::post('{cv}/sended', 'CVController@updateSendStatus')
|
||||||
|
->name('sended');
|
||||||
|
Route::post('', 'CVController@store')
|
||||||
|
->name('store');
|
||||||
|
Route::get('{cv}/edit', 'CVController@edit')
|
||||||
|
->name('edit');
|
||||||
|
Route::put('{cv}', 'CVController@update')
|
||||||
|
->name('update');
|
||||||
|
Route::get('{cv}/delete', 'CVController@delete')
|
||||||
|
->name('delete');
|
||||||
|
Route::delete('{cv}/delete', 'CVController@destroy')
|
||||||
|
->name('destroy');
|
||||||
|
});
|
||||||
|
Route::name('category.')->prefix('category')->group(function (): void {
|
||||||
Route::get('create', 'CategoryController@create')
|
Route::get('create', 'CategoryController@create')
|
||||||
->name('create');
|
->name('create');
|
||||||
Route::post('', 'CategoryController@store')
|
Route::post('', 'CategoryController@store')
|
||||||
@@ -24,7 +76,7 @@ Route::name('admin.')->group(function () {
|
|||||||
->name('destroy');
|
->name('destroy');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::name('project.')->prefix('project')->group(function () {
|
Route::name('project.')->prefix('project')->group(function (): void {
|
||||||
Route::get('create', 'ProjectController@create')
|
Route::get('create', 'ProjectController@create')
|
||||||
->name('create');
|
->name('create');
|
||||||
Route::post('', 'ProjectController@store')
|
Route::post('', 'ProjectController@store')
|
||||||
@@ -42,7 +94,7 @@ Route::name('admin.')->group(function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::name('auth.')->namespace('Auth')->group(function () {
|
Route::name('auth.')->namespace('Auth')->group(function (): void {
|
||||||
Route::get('login', 'LoginController@login')
|
Route::get('login', 'LoginController@login')
|
||||||
->name('login');
|
->name('login');
|
||||||
Route::post('login', 'LoginController@authenticate')
|
Route::post('login', 'LoginController@authenticate')
|
||||||
|
12
tailwind.config.js
vendored
12
tailwind.config.js
vendored
@@ -6,7 +6,17 @@ module.exports = {
|
|||||||
"./resources/views/**/*.blade.php"
|
"./resources/views/**/*.blade.php"
|
||||||
],
|
],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {},
|
extend: {
|
||||||
|
fontFamily: {
|
||||||
|
'arial': ['Arial', 'sans-serif'],
|
||||||
|
'roboto': ['Roboto', 'sans-serif'],
|
||||||
|
'thasadith': ['Thasadith', 'sans-serif'],
|
||||||
|
},
|
||||||
|
colors: {
|
||||||
|
'logo-green': 'rgb(var(--color-logo-green) / <alpha-value>)',
|
||||||
|
'kamilcraft-green': 'rgb(var(--color-logo-green) / <alpha-value>)',
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
plugins: [],
|
plugins: [],
|
||||||
}
|
}
|
||||||
|
70
vite.config.js
vendored
70
vite.config.js
vendored
@@ -1,39 +1,43 @@
|
|||||||
import { defineConfig } from 'vite';
|
import { defineConfig, loadEnv } from 'vite';
|
||||||
import vue from '@vitejs/plugin-vue';
|
import vue from '@vitejs/plugin-vue';
|
||||||
import laravel from 'laravel-vite-plugin';
|
import laravel from 'laravel-vite-plugin';
|
||||||
import { networkInterfaces } from 'os'
|
import { networkInterfaces } from 'os';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig((mode) => {
|
||||||
server: {
|
const env = loadEnv(mode, process.cwd(), "");
|
||||||
host: Object.values(networkInterfaces()).flat().find(i => i.family === 'IPv4' && !i.internal).address,
|
return {
|
||||||
hmr: {
|
server: {
|
||||||
host: 'localhost',
|
host: Object.values(networkInterfaces()).flat().find(i => i.family === 'IPv4' && !i.internal).address,
|
||||||
},
|
port: parseInt(env.VITE_PORT ?? 3001),
|
||||||
},
|
hmr: {
|
||||||
resolve: {
|
host: 'localhost',
|
||||||
alias: {
|
|
||||||
'@': '/resources/js',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
vue({
|
|
||||||
template: {
|
|
||||||
transformAssetUrls: {
|
|
||||||
base: null,
|
|
||||||
includeAbsolute: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
laravel({
|
resolve: {
|
||||||
input: 'resources/js/app.js',
|
alias: {
|
||||||
ssr: 'resources/js/ssr.js',
|
'@': '/resources/js',
|
||||||
refresh: true,
|
},
|
||||||
}),
|
},
|
||||||
],
|
plugins: [
|
||||||
ssr: {
|
vue({
|
||||||
noExternal: [
|
template: {
|
||||||
'@inertiajs/server',
|
transformAssetUrls: {
|
||||||
'@vue/runtime-dom'
|
base: null,
|
||||||
|
includeAbsolute: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
laravel({
|
||||||
|
input: 'resources/js/app.js',
|
||||||
|
ssr: 'resources/js/ssr.js',
|
||||||
|
refresh: true,
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
},
|
ssr: {
|
||||||
|
noExternal: [
|
||||||
|
'@inertiajs/server',
|
||||||
|
'@vue/runtime-dom'
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
6
webpack.mix.js
vendored
6
webpack.mix.js
vendored
@@ -1,6 +0,0 @@
|
|||||||
const mix = require('laravel-mix');
|
|
||||||
|
|
||||||
mix.js('resources/js/app.js', 'public/js');
|
|
||||||
|
|
||||||
mix.sass('resources/sass/app.scss', 'public/css');
|
|
||||||
mix.sass('resources/sass/dashboard.scss', 'public/css');
|
|
Reference in New Issue
Block a user