#4- wip
This commit is contained in:
parent
7dca5d1e6c
commit
acf2eba95d
@ -15,4 +15,14 @@ enum FormOfEmployment: string
|
||||
{
|
||||
return __($this->value);
|
||||
}
|
||||
|
||||
public static function casesToSelect(): array
|
||||
{
|
||||
$cases = collect(FormOfEmployment::cases());
|
||||
|
||||
return $cases->map(fn(FormOfEmployment $enum) => [
|
||||
"label" => $enum->label(),
|
||||
"value" => $enum->value]
|
||||
)->toArray();
|
||||
}
|
||||
}
|
@ -4,8 +4,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace Toby\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Inertia\Response;
|
||||
use Toby\Enums\FormOfEmployment;
|
||||
use Toby\Http\Requests\UserRequest;
|
||||
use Toby\Http\Resources\UserFormDataResource;
|
||||
use Toby\Http\Resources\UserResource;
|
||||
use Toby\Models\User;
|
||||
|
||||
@ -14,6 +18,7 @@ class UserController extends Controller
|
||||
public function index(Request $request): Response
|
||||
{
|
||||
$users = User::query()
|
||||
->withTrashed()
|
||||
->search($request->query("search"))
|
||||
->paginate()
|
||||
->withQueryString();
|
||||
@ -23,4 +28,55 @@ class UserController extends Controller
|
||||
"filters" => $request->only("search"),
|
||||
]);
|
||||
}
|
||||
|
||||
public function create(): Response
|
||||
{
|
||||
return inertia("Users/Create", [
|
||||
"employmentForms" => FormOfEmployment::casesToSelect(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(UserRequest $request): RedirectResponse
|
||||
{
|
||||
User::query()->create($request->data());
|
||||
|
||||
return redirect()
|
||||
->route("users.index")
|
||||
->with("success", __("User has been created"));
|
||||
}
|
||||
|
||||
public function edit(User $user): Response
|
||||
{
|
||||
return inertia("Users/Edit", [
|
||||
"user" => new UserFormDataResource($user),
|
||||
"employmentForms" => FormOfEmployment::casesToSelect()
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(UserRequest $request, User $user): RedirectResponse
|
||||
{
|
||||
$user->update($request->data());
|
||||
|
||||
return redirect()
|
||||
->route("users.index")
|
||||
->with("success", __("User has been updated"));
|
||||
}
|
||||
|
||||
public function destroy(User $user): RedirectResponse
|
||||
{
|
||||
$user->delete();
|
||||
|
||||
return redirect()
|
||||
->route("users.index")
|
||||
->with("success", __("User has been deleted"));
|
||||
}
|
||||
|
||||
public function restore(User $user): RedirectResponse
|
||||
{
|
||||
$user->restore();
|
||||
|
||||
return redirect()
|
||||
->route("users.index")
|
||||
->with("success", __("User has been restored"));
|
||||
}
|
||||
}
|
||||
|
33
app/Http/Requests/UserRequest.php
Normal file
33
app/Http/Requests/UserRequest.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Toby\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
use Toby\Enums\FormOfEmployment;
|
||||
|
||||
class UserRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
"name" => ["required", "min:3", "max: 150"],
|
||||
"email" => ["required", "email", Rule::unique("users", "email")->ignore($this->user)],
|
||||
"employmentForm" => ["required", new Enum(FormOfEmployment::class)],
|
||||
"employmentDate" => ["required", "date"],
|
||||
];
|
||||
}
|
||||
|
||||
public function data(): array
|
||||
{
|
||||
return [
|
||||
"name" => $this->get("name"),
|
||||
"email" => $this->get("email"),
|
||||
"employment_form" => $this->get("employmentForm"),
|
||||
"employment_date" => $this->get("employmentDate"),
|
||||
];
|
||||
}
|
||||
}
|
23
app/Http/Resources/UserFormDataResource.php
Normal file
23
app/Http/Resources/UserFormDataResource.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Toby\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class UserFormDataResource extends JsonResource
|
||||
{
|
||||
public static $wrap = false;
|
||||
|
||||
public function toArray($request): array
|
||||
{
|
||||
return [
|
||||
"id" => $this->id,
|
||||
"name" => $this->name,
|
||||
"email" => $this->email,
|
||||
"employmentForm" => $this->employment_form,
|
||||
"employmentDate" => $this->employment_date,
|
||||
];
|
||||
}
|
||||
}
|
@ -16,8 +16,9 @@ class UserResource extends JsonResource
|
||||
"email" => $this->email,
|
||||
"role" => "Human Resources Manager",
|
||||
"avatar" => asset($this->avatar),
|
||||
"trashed" => $this->trashed(),
|
||||
"employmentForm" => $this->employment_form->label(),
|
||||
"employmentStartDate" => $this->employment_start_date->translatedFormat("j F Y"),
|
||||
"employmentDate" => $this->employment_date->translatedFormat("j F Y"),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ namespace Toby\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Illuminate\Support\Carbon;
|
||||
@ -17,12 +18,13 @@ use Toby\Enums\FormOfEmployment;
|
||||
* @property string $email
|
||||
* @property string $avatar
|
||||
* @property FormOfEmployment $employment_form
|
||||
* @property Carbon $empoyment_start_date
|
||||
* @property Carbon $empoyment_date
|
||||
*/
|
||||
class User extends Authenticatable
|
||||
{
|
||||
use HasFactory;
|
||||
use Notifiable;
|
||||
use SoftDeletes;
|
||||
|
||||
protected $perPage = 10;
|
||||
|
||||
@ -31,12 +33,12 @@ class User extends Authenticatable
|
||||
"email",
|
||||
"avatar",
|
||||
"employment_form",
|
||||
"employment_start_date",
|
||||
"employment_date",
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
"employment_form" => FormOfEmployment::class,
|
||||
"employment_start_date" => "datetime",
|
||||
"employment_date" => "datetime",
|
||||
];
|
||||
|
||||
protected $hidden = [
|
||||
|
@ -29,7 +29,7 @@ class UserObserver
|
||||
}
|
||||
}
|
||||
|
||||
public function deleted(User $user): void
|
||||
public function forceDeleted(User $user): void
|
||||
{
|
||||
Storage::delete($user->avatar);
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ class UserFactory extends Factory
|
||||
"name" => "{$this->faker->firstName} {$this->faker->lastName}",
|
||||
"email" => $this->faker->unique()->safeEmail(),
|
||||
"employment_form" => $this->faker->randomElement(FormOfEmployment::cases()),
|
||||
"employment_start_date" => $this->faker->dateTimeBetween("2020-10-27"),
|
||||
"employment_date" => $this->faker->dateTimeBetween("2020-10-27"),
|
||||
"remember_token" => Str::random(10),
|
||||
];
|
||||
}
|
||||
|
@ -15,8 +15,9 @@ return new class() extends Migration {
|
||||
$table->string("email")->unique();
|
||||
$table->string("avatar")->nullable();
|
||||
$table->string("employment_form");
|
||||
$table->dateTime("employment_start_date");
|
||||
$table->dateTime("employment_date");
|
||||
$table->rememberToken();
|
||||
$table->softDeletes();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
34
package-lock.json
generated
34
package-lock.json
generated
@ -15,11 +15,13 @@
|
||||
"@tailwindcss/typography": "^0.5.0",
|
||||
"@vue/compiler-sfc": "^3.2.26",
|
||||
"autoprefixer": "^10.4.2",
|
||||
"flatpickr": "^4.6.9",
|
||||
"laravel-mix": "^6.0.6",
|
||||
"lodash": "^4.17.21",
|
||||
"postcss": "^8.4.5",
|
||||
"tailwindcss": "^3.0.13",
|
||||
"vue": "^3.2.26",
|
||||
"vue-flatpickr-component": "^9.0.5",
|
||||
"vue-loader": "^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -4723,6 +4725,11 @@
|
||||
"node": "^10.12.0 || >=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/flatpickr": {
|
||||
"version": "4.6.9",
|
||||
"resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.9.tgz",
|
||||
"integrity": "sha512-F0azNNi8foVWKSF+8X+ZJzz8r9sE1G4hl06RyceIaLvyltKvDl6vqk9Lm/6AUUCi5HWaIjiUbk7UpeE/fOXOpw=="
|
||||
},
|
||||
"node_modules/flatted": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz",
|
||||
@ -8893,6 +8900,20 @@
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-flatpickr-component": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/vue-flatpickr-component/-/vue-flatpickr-component-9.0.5.tgz",
|
||||
"integrity": "sha512-fKuz/D4ePQKi+jPo4xjYRgBCLTWrTsCoKbx8nam63x4kTDtSqvFOjNwLvy0QgwC0lC+aFpUWa1dNYTH0hgUcCA==",
|
||||
"dependencies": {
|
||||
"flatpickr": "^4.6.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-loader": {
|
||||
"version": "17.0.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-17.0.0.tgz",
|
||||
@ -12983,6 +13004,11 @@
|
||||
"rimraf": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"flatpickr": {
|
||||
"version": "4.6.9",
|
||||
"resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.9.tgz",
|
||||
"integrity": "sha512-F0azNNi8foVWKSF+8X+ZJzz8r9sE1G4hl06RyceIaLvyltKvDl6vqk9Lm/6AUUCi5HWaIjiUbk7UpeE/fOXOpw=="
|
||||
},
|
||||
"flatted": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz",
|
||||
@ -15971,6 +15997,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"vue-flatpickr-component": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/vue-flatpickr-component/-/vue-flatpickr-component-9.0.5.tgz",
|
||||
"integrity": "sha512-fKuz/D4ePQKi+jPo4xjYRgBCLTWrTsCoKbx8nam63x4kTDtSqvFOjNwLvy0QgwC0lC+aFpUWa1dNYTH0hgUcCA==",
|
||||
"requires": {
|
||||
"flatpickr": "^4.6.9"
|
||||
}
|
||||
},
|
||||
"vue-loader": {
|
||||
"version": "17.0.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-17.0.0.tgz",
|
||||
|
@ -22,11 +22,13 @@
|
||||
"@tailwindcss/typography": "^0.5.0",
|
||||
"@vue/compiler-sfc": "^3.2.26",
|
||||
"autoprefixer": "^10.4.2",
|
||||
"flatpickr": "^4.6.9",
|
||||
"laravel-mix": "^6.0.6",
|
||||
"lodash": "^4.17.21",
|
||||
"postcss": "^8.4.5",
|
||||
"tailwindcss": "^3.0.13",
|
||||
"vue": "^3.2.26",
|
||||
"vue-flatpickr-component": "^9.0.5",
|
||||
"vue-loader": "^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -1,3 +1,49 @@
|
||||
@import 'flatpickr/dist/themes/light.css';
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
|
||||
.flatpickr-months .flatpickr-prev-month:hover svg,
|
||||
.flatpickr-months .flatpickr-next-month:hover svg {
|
||||
fill: #4F46E5;
|
||||
}
|
||||
|
||||
.flatpickr-day.selected,
|
||||
.flatpickr-day.startRange,
|
||||
.flatpickr-day.endRange,
|
||||
.flatpickr-day.selected.inRange,
|
||||
.flatpickr-day.startRange.inRange,
|
||||
.flatpickr-day.endRange.inRange,
|
||||
.flatpickr-day.selected:focus,
|
||||
.flatpickr-day.startRange:focus,
|
||||
.flatpickr-day.endRange:focus,
|
||||
.flatpickr-day.selected:hover,
|
||||
.flatpickr-day.startRange:hover,
|
||||
.flatpickr-day.endRange:hover,
|
||||
.flatpickr-day.selected.prevMonthDay,
|
||||
.flatpickr-day.startRange.prevMonthDay,
|
||||
.flatpickr-day.endRange.prevMonthDay,
|
||||
.flatpickr-day.selected.nextMonthDay,
|
||||
.flatpickr-day.startRange.nextMonthDay,
|
||||
.flatpickr-day.endRange.nextMonthDay {
|
||||
background: #527ABA;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
color: #fff;
|
||||
border-color: #527ABA;
|
||||
}
|
||||
|
||||
.flatpickr-day.selected.startRange + .endRange:not(:nth-child(7n+1)),
|
||||
.flatpickr-day.startRange.startRange + .endRange:not(:nth-child(7n+1)),
|
||||
.flatpickr-day.endRange.startRange + .endRange:not(:nth-child(7n+1)) {
|
||||
-webkit-box-shadow: -10px 0 0 #527ABA;
|
||||
box-shadow: -10px 0 0 #527ABA;
|
||||
}
|
||||
|
||||
.flatpickr-day.week.selected {
|
||||
border-radius: 0;
|
||||
-webkit-box-shadow: -5px 0 0 #527ABA, 5px 0 0 #527ABA;
|
||||
box-shadow: -5px 0 0 #527ABA, 5px 0 0 #527ABA;
|
||||
}
|
162
resources/js/Pages/Users/Create.vue
Normal file
162
resources/js/Pages/Users/Create.vue
Normal file
@ -0,0 +1,162 @@
|
||||
<template>
|
||||
<InertiaHead title="Dodawanie użytkownika" />
|
||||
<div class="bg-white sm:rounded-lg shadow-md">
|
||||
<div class="p-4 sm:px-6">
|
||||
<h2 class="text-lg leading-6 font-medium text-gray-900">
|
||||
Dodaj użytkownika
|
||||
</h2>
|
||||
<p class="mt-1 text-sm text-gray-500">
|
||||
Tylko dodani użytkownicy będą mogli zalogować się do aplikacji.
|
||||
</p>
|
||||
</div>
|
||||
<form
|
||||
class="border-t border-gray-200 px-6 divide-y"
|
||||
@submit.prevent="form.post('/users')"
|
||||
>
|
||||
<div class="sm:grid sm:grid-cols-3 py-4 items-center">
|
||||
<label
|
||||
for="name"
|
||||
class="block text-sm font-medium text-gray-700 sm:mt-px"
|
||||
>
|
||||
Imię i nazwisko
|
||||
</label>
|
||||
<div class="mt-1 sm:mt-0 sm:col-span-2">
|
||||
<input
|
||||
id="name"
|
||||
v-model="form.name"
|
||||
type="text"
|
||||
class="block w-full max-w-lg shadow-sm rounded-md sm:text-sm"
|
||||
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors.name, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors.name }"
|
||||
>
|
||||
<p
|
||||
v-if="form.errors.name"
|
||||
class="mt-2 text-sm text-red-600"
|
||||
>
|
||||
{{ form.errors.name }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sm:grid sm:grid-cols-3 py-4 items-center">
|
||||
<label
|
||||
for="email"
|
||||
class="block text-sm font-medium text-gray-700 sm:mt-px"
|
||||
>
|
||||
Adres email
|
||||
</label>
|
||||
<div class="mt-1 sm:mt-0 sm:col-span-2">
|
||||
<input
|
||||
id="email"
|
||||
v-model="form.email"
|
||||
type="email"
|
||||
class="block w-full max-w-lg shadow-sm rounded-md sm:text-sm"
|
||||
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors.email, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors.email }"
|
||||
>
|
||||
<p
|
||||
v-if="form.errors.email"
|
||||
class="mt-2 text-sm text-red-600"
|
||||
>
|
||||
{{ form.errors.email }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sm:grid sm:grid-cols-3 py-4 items-center">
|
||||
<label
|
||||
for="employment_form"
|
||||
class="block text-sm font-medium text-gray-700 sm:mt-px"
|
||||
>
|
||||
Forma zatrudnienia
|
||||
</label>
|
||||
<div class="mt-1 sm:mt-0 sm:col-span-2">
|
||||
<select
|
||||
id="employment_form"
|
||||
v-model="form.employmentForm"
|
||||
class="block w-full max-w-lg shadow-sm rounded-md sm:text-sm"
|
||||
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors.employmentForm, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors.employmentForm }"
|
||||
>
|
||||
<option
|
||||
v-for="employmentForm in employmentForms"
|
||||
:key="employmentForm.value"
|
||||
:value="employmentForm.value"
|
||||
>
|
||||
{{ employmentForm.label }}
|
||||
</option>
|
||||
</select>
|
||||
<p
|
||||
v-if="form.errors.employmentForm"
|
||||
class="mt-2 text-sm text-red-600"
|
||||
>
|
||||
{{ form.errors.employmentForm }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sm:grid sm:grid-cols-3 py-4 items-center">
|
||||
<label
|
||||
for="employment_date"
|
||||
class="block text-sm font-medium text-gray-700 sm:mt-px"
|
||||
>
|
||||
Data zatrudnienia
|
||||
</label>
|
||||
<div class="mt-1 sm:mt-0 sm:col-span-2">
|
||||
<FlatPickr
|
||||
id="employment_date"
|
||||
v-model="form.employmentDate"
|
||||
placeholder="Wybierz datę"
|
||||
class="block w-full max-w-lg shadow-sm rounded-md sm:text-sm"
|
||||
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors.employmentDate, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors.employmentDate }"
|
||||
/>
|
||||
<p
|
||||
v-if="form.errors.employmentDate"
|
||||
class="mt-2 text-sm text-red-600"
|
||||
>
|
||||
{{ form.errors.employmentDate }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end py-3">
|
||||
<div class="space-x-3">
|
||||
<InertiaLink
|
||||
href="/users"
|
||||
class="bg-white py-2 px-4 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blumilk-500"
|
||||
>
|
||||
Anuluj
|
||||
</InertiaLink>
|
||||
<button
|
||||
type="submit"
|
||||
:disabled="form.processing"
|
||||
class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-blumilk-600 hover:bg-blumilk-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blumilk-500"
|
||||
>
|
||||
Zapisz
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {useForm} from '@inertiajs/inertia-vue3';
|
||||
import FlatPickr from 'vue-flatpickr-component';
|
||||
|
||||
export default {
|
||||
employmentDate: 'UserCreate',
|
||||
components: {
|
||||
FlatPickr,
|
||||
},
|
||||
props: {
|
||||
employmentForms: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const form = useForm({
|
||||
name: null,
|
||||
email: null,
|
||||
employmentForm: props.employmentForms[0].value,
|
||||
employmentDate: new Date(),
|
||||
});
|
||||
|
||||
return { form };
|
||||
}
|
||||
};
|
||||
</script>
|
166
resources/js/Pages/Users/Edit.vue
Normal file
166
resources/js/Pages/Users/Edit.vue
Normal file
@ -0,0 +1,166 @@
|
||||
<template>
|
||||
<InertiaHead title="Edycja użytkownika" />
|
||||
<div class="bg-white sm:rounded-lg shadow-md">
|
||||
<div class="p-4 sm:px-6">
|
||||
<h2 class="text-lg leading-6 font-medium text-gray-900">
|
||||
Edytuj użytkownika
|
||||
</h2>
|
||||
<p class="mt-1 text-sm text-gray-500">
|
||||
Edytuj dane użytkownika, takie jak email czy formę zatrudnienia.
|
||||
</p>
|
||||
</div>
|
||||
<form
|
||||
class="border-t border-gray-200 px-6 divide-y"
|
||||
@submit.prevent="form.put(`/users/${user.id}`)"
|
||||
>
|
||||
<div class="sm:grid sm:grid-cols-3 py-4 items-center">
|
||||
<label
|
||||
for="name"
|
||||
class="block text-sm font-medium text-gray-700 sm:mt-px"
|
||||
>
|
||||
Imię i nazwisko
|
||||
</label>
|
||||
<div class="mt-1 sm:mt-0 sm:col-span-2">
|
||||
<input
|
||||
id="name"
|
||||
v-model="form.name"
|
||||
type="text"
|
||||
class="block w-full max-w-lg shadow-sm rounded-md sm:text-sm"
|
||||
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors.name, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors.name }"
|
||||
>
|
||||
<p
|
||||
v-if="form.errors.name"
|
||||
class="mt-2 text-sm text-red-600"
|
||||
>
|
||||
{{ form.errors.name }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sm:grid sm:grid-cols-3 py-4 items-center">
|
||||
<label
|
||||
for="email"
|
||||
class="block text-sm font-medium text-gray-700 sm:mt-px"
|
||||
>
|
||||
Adres email
|
||||
</label>
|
||||
<div class="mt-1 sm:mt-0 sm:col-span-2">
|
||||
<input
|
||||
id="email"
|
||||
v-model="form.email"
|
||||
type="email"
|
||||
class="block w-full max-w-lg shadow-sm rounded-md sm:text-sm"
|
||||
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors.email, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors.email }"
|
||||
>
|
||||
<p
|
||||
v-if="form.errors.email"
|
||||
class="mt-2 text-sm text-red-600"
|
||||
>
|
||||
{{ form.errors.email }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sm:grid sm:grid-cols-3 py-4 items-center">
|
||||
<label
|
||||
for="employment_form"
|
||||
class="block text-sm font-medium text-gray-700 sm:mt-px"
|
||||
>
|
||||
Forma zatrudnienia
|
||||
</label>
|
||||
<div class="mt-1 sm:mt-0 sm:col-span-2">
|
||||
<select
|
||||
id="employment_form"
|
||||
v-model="form.employmentForm"
|
||||
class="block w-full max-w-lg shadow-sm rounded-md sm:text-sm"
|
||||
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors.employmentForm, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors.employmentForm }"
|
||||
>
|
||||
<option
|
||||
v-for="employmentForm in employmentForms"
|
||||
:key="employmentForm.value"
|
||||
:value="employmentForm.value"
|
||||
>
|
||||
{{ employmentForm.label }}
|
||||
</option>
|
||||
</select>
|
||||
<p
|
||||
v-if="form.errors.employmentForm"
|
||||
class="mt-2 text-sm text-red-600"
|
||||
>
|
||||
{{ form.errors.employmentForm }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sm:grid sm:grid-cols-3 py-4 items-center">
|
||||
<label
|
||||
for="employment_date"
|
||||
class="block text-sm font-medium text-gray-700 sm:mt-px"
|
||||
>
|
||||
Data zatrudnienia
|
||||
</label>
|
||||
<div class="mt-1 sm:mt-0 sm:col-span-2">
|
||||
<FlatPickr
|
||||
id="employment_date"
|
||||
v-model="form.employmentDate"
|
||||
placeholder="Wybierz datę"
|
||||
class="block w-full max-w-lg shadow-sm rounded-md sm:text-sm"
|
||||
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors.employmentDate, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors.employmentDate }"
|
||||
/>
|
||||
<p
|
||||
v-if="form.errors.employmentDate"
|
||||
class="mt-2 text-sm text-red-600"
|
||||
>
|
||||
{{ form.errors.employmentDate }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end py-3">
|
||||
<div class="space-x-3">
|
||||
<InertiaLink
|
||||
href="/users"
|
||||
class="bg-white py-2 px-4 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blumilk-500"
|
||||
>
|
||||
Anuluj
|
||||
</InertiaLink>
|
||||
<button
|
||||
type="submit"
|
||||
:disabled="form.processing"
|
||||
class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-blumilk-600 hover:bg-blumilk-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blumilk-500"
|
||||
>
|
||||
Zapisz
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {useForm} from '@inertiajs/inertia-vue3';
|
||||
import FlatPickr from 'vue-flatpickr-component';
|
||||
|
||||
export default {
|
||||
employmentDate: 'UserEdit',
|
||||
components: {
|
||||
FlatPickr,
|
||||
},
|
||||
props: {
|
||||
employmentForms: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
},
|
||||
user: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const form = useForm({
|
||||
name: props.user.name,
|
||||
email: props.user.email,
|
||||
employmentForm: props.user.employmentForm,
|
||||
employmentDate: new Date(props.user.employmentDate),
|
||||
});
|
||||
|
||||
return { form };
|
||||
}
|
||||
};
|
||||
</script>
|
@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<InertiaHead title="Użytkownicy" />
|
||||
<div class="bg-white sm:rounded-lg shadow-md">
|
||||
<div class="p-4 sm:px-6">
|
||||
<div class="flex justify-between items-center p-4 sm:px-6">
|
||||
<div>
|
||||
<h2 class="text-lg leading-6 font-medium text-gray-900">
|
||||
Użytkownicy w organizacji
|
||||
</h2>
|
||||
@ -9,6 +10,15 @@
|
||||
Lista użytkowników w organizacji.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<InertiaLink
|
||||
href="users/create"
|
||||
class="inline-flex items-center px-4 py-3 border border-transparent text-sm leading-4 font-medium rounded-md shadow-sm text-white bg-blumilk-600 hover:bg-blumilk-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blumilk-500"
|
||||
>
|
||||
Dodaj użytkownika
|
||||
</InertiaLink>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border-t border-gray-200">
|
||||
<div class="px-4 py-3">
|
||||
<div class="relative max-w-md">
|
||||
@ -61,7 +71,7 @@
|
||||
<tr
|
||||
v-for="user in users.data"
|
||||
:key="user.id"
|
||||
class="hover:bg-white"
|
||||
:class="{ 'bg-red-50': user.trashed, 'hover:bg-blumilk-25': !user.trashed }"
|
||||
>
|
||||
<td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
<div class="flex">
|
||||
@ -91,25 +101,72 @@
|
||||
{{ user.employmentForm }}
|
||||
</td>
|
||||
<td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{{ user.employmentStartDate }}
|
||||
{{ user.employmentDate }}
|
||||
</td>
|
||||
<td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500 text-right">
|
||||
<div>
|
||||
<button
|
||||
class="rounded-full flex items-center text-gray-400 hover:text-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-100 focus:ring-blumilk-500"
|
||||
<Menu
|
||||
as="div"
|
||||
class="relative inline-block text-left"
|
||||
>
|
||||
<svg
|
||||
<MenuButton class="rounded-full flex items-center text-gray-400 hover:text-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-100 focus:ring-blumilk-500">
|
||||
<DotsVerticalIcon
|
||||
class="h-5 w-5"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
d="M10 6a2 2 0 110-4 2 2 0 010 4zM10 12a2 2 0 110-4 2 2 0 010 4zM10 18a2 2 0 110-4 2 2 0 010 4z"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</MenuButton>
|
||||
|
||||
<transition
|
||||
enter-active-class="transition ease-out duration-100"
|
||||
enter-from-class="transform opacity-0 scale-95"
|
||||
enter-to-class="transform opacity-100 scale-100"
|
||||
leave-active-class="transition ease-in duration-75"
|
||||
leave-from-class="transform opacity-100 scale-100"
|
||||
leave-to-class="transform opacity-0 scale-95"
|
||||
>
|
||||
<MenuItems class="origin-top-right absolute right-0 mt-2 w-56 z-10 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none">
|
||||
<div
|
||||
v-if="!user.trashed"
|
||||
class="py-1"
|
||||
>
|
||||
<MenuItem v-slot="{ active }">
|
||||
<InertiaLink
|
||||
:href="`/users/${user.id}/edit`"
|
||||
:class="[active ? 'bg-gray-100 text-gray-900' : 'text-gray-700', 'block px-4 py-2 text-sm']"
|
||||
>
|
||||
Edytuj
|
||||
</InertiaLink>
|
||||
</MenuItem>
|
||||
<MenuItem v-slot="{ active }">
|
||||
<InertiaLink
|
||||
as="button"
|
||||
method="delete"
|
||||
:preserve-scroll="true"
|
||||
:href="`/users/${user.id}`"
|
||||
:class="[active ? 'bg-gray-100 text-gray-900' : 'text-gray-700', 'block w-full text-left px-4 py-2 text-sm']"
|
||||
>
|
||||
Usuń
|
||||
</InertiaLink>
|
||||
</MenuItem>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="py-1"
|
||||
>
|
||||
<MenuItem v-slot="{ active }">
|
||||
<InertiaLink
|
||||
as="button"
|
||||
method="post"
|
||||
:preserve-scroll="true"
|
||||
:href="`/users/${user.id}/restore`"
|
||||
:class="[active ? 'bg-gray-100 text-gray-900' : 'text-gray-700', 'block w-full text-left px-4 py-2 text-sm']"
|
||||
>
|
||||
Przywróć
|
||||
</InertiaLink>
|
||||
</MenuItem>
|
||||
</div>
|
||||
</MenuItems>
|
||||
</transition>
|
||||
</Menu>
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
@ -162,6 +219,7 @@
|
||||
<Component
|
||||
:is="link.url ? 'InertiaLink' : 'span'"
|
||||
:href="link.url"
|
||||
:preserve-scroll="true"
|
||||
class="relative inline-flex items-center px-4 py-2 border rounded-md text-sm font-medium"
|
||||
:class="{ 'z-10 bg-blumilk-25 border-blumilk-500 text-blumilk-600': link.active, 'bg-white border-gray-300 text-gray-500': !link.active, 'hover:bg-blumilk-25': link.url, 'border-none': !link.url}"
|
||||
v-text="link.label"
|
||||
@ -180,11 +238,18 @@ import { ref, watch } from 'vue';
|
||||
import { Inertia } from '@inertiajs/inertia';
|
||||
import { debounce } from 'lodash';
|
||||
import { SearchIcon } from '@heroicons/vue/outline';
|
||||
import {DotsVerticalIcon} from '@heroicons/vue/solid';
|
||||
import {Menu, MenuButton, MenuItem, MenuItems} from '@headlessui/vue';
|
||||
|
||||
export default {
|
||||
name: 'UserIndex',
|
||||
components: {
|
||||
SearchIcon,
|
||||
DotsVerticalIcon,
|
||||
Menu,
|
||||
MenuButton,
|
||||
MenuItem,
|
||||
MenuItems,
|
||||
},
|
||||
props: {
|
||||
users: {
|
||||
|
@ -2,6 +2,8 @@ import {createApp, h} from 'vue';
|
||||
import {createInertiaApp, Head, Link} from '@inertiajs/inertia-vue3';
|
||||
import {InertiaProgress} from '@inertiajs/progress';
|
||||
import AppLayout from '@/Shared/Layout/AppLayout';
|
||||
import Flatpickr from 'flatpickr';
|
||||
import { Polish } from 'flatpickr/dist/l10n/pl.js';
|
||||
|
||||
createInertiaApp({
|
||||
resolve: name => {
|
||||
@ -25,3 +27,12 @@ InertiaProgress.init({
|
||||
delay: 0,
|
||||
color: 'red',
|
||||
});
|
||||
|
||||
Flatpickr.localize(Polish);
|
||||
Flatpickr.setDefaults({
|
||||
dateFormat: 'Y-m-d',
|
||||
enableTime: false,
|
||||
altFormat: 'j F Y',
|
||||
altInput: true
|
||||
});
|
||||
|
||||
|
@ -12,7 +12,7 @@ Route::middleware("auth")->group(function (): void {
|
||||
Route::post("/logout", LogoutController::class);
|
||||
|
||||
Route::resource("users", UserController::class);
|
||||
|
||||
Route::post("users/{user}/restore", [UserController::class, "restore"])->withTrashed();
|
||||
});
|
||||
|
||||
Route::middleware("guest")->group(function (): void {
|
||||
|
Loading…
x
Reference in New Issue
Block a user