diff --git a/.env.example b/.env.example
index b4d8f7a..0499d29 100644
--- a/.env.example
+++ b/.env.example
@@ -54,3 +54,5 @@ DOCKER_INSTALL_XDEBUG=false
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GOOGLE_REDIRECT=
+
+LOCAL_EMAIL_FOR_LOGIN_VIA_GOOGLE=
diff --git a/.eslintrc.js b/.eslintrc.js
index 898a3a0..5245fdc 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -12,5 +12,6 @@ module.exports = {
indent: ['error', 4],
'vue/html-indent': ['error', 4],
'vue/multi-word-component-names': 'off',
- }
+ 'comma-dangle': ['error', 'always-multiline'],
+ },
};
diff --git a/app/Console/Commands/CreateUserCommand.php b/app/Console/Commands/CreateUserCommand.php
new file mode 100644
index 0000000..34c6dec
--- /dev/null
+++ b/app/Console/Commands/CreateUserCommand.php
@@ -0,0 +1,26 @@
+argument("email");
+
+ User::factory([
+ "email" => $email,
+ ])->create();
+
+ $this->info("The user has been created");
+ }
+}
diff --git a/app/Enums/EmploymentForm.php b/app/Enums/EmploymentForm.php
new file mode 100644
index 0000000..27c1bb7
--- /dev/null
+++ b/app/Enums/EmploymentForm.php
@@ -0,0 +1,30 @@
+value);
+ }
+
+ public static function casesToSelect(): array
+ {
+ $cases = collect(EmploymentForm::cases());
+
+ return $cases->map(
+ fn(EmploymentForm $enum) => [
+ "label" => $enum->label(),
+ "value" => $enum->value,
+ ],
+ )->toArray();
+ }
+}
diff --git a/app/Helpers/UserAvatarGenerator.php b/app/Helpers/UserAvatarGenerator.php
new file mode 100644
index 0000000..beb39c7
--- /dev/null
+++ b/app/Helpers/UserAvatarGenerator.php
@@ -0,0 +1,50 @@
+generateUuid()}.svg";
+
+ Storage::put($path, $this->generate($user));
+
+ return $path;
+ }
+
+ protected function generate(User $user): SVG
+ {
+ return $this->generator->rounded()
+ ->background($this->getColor($user->name))
+ ->color("#F4F8FD")
+ ->smooth()
+ ->fontSize(0.33)
+ ->generateSvg($user->name);
+ }
+
+ protected function getColor(string $name): string
+ {
+ $colors = config("colors");
+
+ return $colors[strlen($name) % count($colors)];
+ }
+
+ protected function generateUuid(): string
+ {
+ return Str::uuid()->toString();
+ }
+}
diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php
new file mode 100644
index 0000000..a390687
--- /dev/null
+++ b/app/Http/Controllers/UserController.php
@@ -0,0 +1,83 @@
+withTrashed()
+ ->search($request->query("search"))
+ ->latest()
+ ->paginate()
+ ->withQueryString();
+
+ return inertia("Users/Index", [
+ "users" => UserResource::collection($users),
+ "filters" => $request->only("search"),
+ ]);
+ }
+
+ public function create(): Response
+ {
+ return inertia("Users/Create", [
+ "employmentForms" => EmploymentForm::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" => EmploymentForm::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"));
+ }
+}
diff --git a/app/Http/Requests/UserRequest.php b/app/Http/Requests/UserRequest.php
new file mode 100644
index 0000000..b1a92a0
--- /dev/null
+++ b/app/Http/Requests/UserRequest.php
@@ -0,0 +1,33 @@
+ ["required", "min:3", "max: 150"],
+ "email" => ["required", "email", Rule::unique("users", "email")->ignore($this->user)],
+ "employmentForm" => ["required", new Enum(EmploymentForm::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"),
+ ];
+ }
+}
diff --git a/app/Http/Resources/UserFormDataResource.php b/app/Http/Resources/UserFormDataResource.php
new file mode 100644
index 0000000..df7da1f
--- /dev/null
+++ b/app/Http/Resources/UserFormDataResource.php
@@ -0,0 +1,23 @@
+ $this->id,
+ "name" => $this->name,
+ "email" => $this->email,
+ "employmentForm" => $this->employment_form,
+ "employmentDate" => $this->employment_date,
+ ];
+ }
+}
diff --git a/app/Http/Resources/UserResource.php b/app/Http/Resources/UserResource.php
index b3e03f0..c9217a6 100644
--- a/app/Http/Resources/UserResource.php
+++ b/app/Http/Resources/UserResource.php
@@ -8,6 +8,8 @@ use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
+ public static $wrap = false;
+
public function toArray($request): array
{
return [
@@ -15,7 +17,10 @@ class UserResource extends JsonResource
"name" => $this->name,
"email" => $this->email,
"role" => "Human Resources Manager",
- "avatar" => "https://images.unsplash.com/photo-1550525811-e5869dd03032?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80",
+ "avatar" => asset($this->avatar),
+ "deleted" => $this->trashed(),
+ "employmentForm" => $this->employment_form->label(),
+ "employmentDate" => $this->employment_date->toDisplayString(),
];
}
}
diff --git a/app/Models/User.php b/app/Models/User.php
index 660b8f7..aa76021 100644
--- a/app/Models/User.php
+++ b/app/Models/User.php
@@ -4,26 +4,53 @@ declare(strict_types=1);
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;
+use Toby\Enums\EmploymentForm;
/**
* @property int $id
* @property string $name
* @property string $email
+ * @property string $avatar
+ * @property EmploymentForm $employment_form
+ * @property Carbon $employment_date
*/
class User extends Authenticatable
{
use HasFactory;
use Notifiable;
+ use SoftDeletes;
protected $fillable = [
"name",
"email",
+ "avatar",
+ "employment_form",
+ "employment_date",
+ ];
+
+ protected $casts = [
+ "employment_form" => EmploymentForm::class,
+ "employment_date" => "datetime",
];
protected $hidden = [
"remember_token",
];
+
+ public function scopeSearch(Builder $query, ?string $text): Builder
+ {
+ if ($text === null) {
+ return $query;
+ }
+
+ return $query
+ ->where("name", "LIKE", "%{$text}%")
+ ->orWhere("email", "LIKE", "%{$text}%");
+ }
}
diff --git a/app/Observers/UserObserver.php b/app/Observers/UserObserver.php
new file mode 100644
index 0000000..32f6f9c
--- /dev/null
+++ b/app/Observers/UserObserver.php
@@ -0,0 +1,37 @@
+avatar = $this->generator->generateFor($user);
+
+ $user->save();
+ }
+
+ public function updating(User $user): void
+ {
+ if ($user->isDirty("name")) {
+ Storage::delete($user->avatar);
+ $user->avatar = $this->generator->generateFor($user);
+ }
+ }
+
+ public function forceDeleted(User $user): void
+ {
+ Storage::delete($user->avatar);
+ }
+}
diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php
index 08b69d4..db3deaa 100644
--- a/app/Providers/AppServiceProvider.php
+++ b/app/Providers/AppServiceProvider.php
@@ -4,8 +4,17 @@ declare(strict_types=1);
namespace Toby\Providers;
+use Illuminate\Support\Carbon;
use Illuminate\Support\ServiceProvider;
+use Toby\Models\User;
+use Toby\Observers\UserObserver;
class AppServiceProvider extends ServiceProvider
{
+ public function boot(): void
+ {
+ User::observe(UserObserver::class);
+
+ Carbon::macro("toDisplayString", fn() => $this->translatedFormat("j F Y"));
+ }
}
diff --git a/composer.json b/composer.json
index d597c15..3d13d3f 100644
--- a/composer.json
+++ b/composer.json
@@ -13,7 +13,8 @@
"laravel/framework": "^8.75",
"laravel/socialite": "^5.2",
"laravel/telescope": "^4.6",
- "laravel/tinker": "^2.5"
+ "laravel/tinker": "^2.5",
+ "lasserafn/php-initial-avatar-generator": "^4.2"
},
"require-dev": {
"blumilksoftware/codestyle": "^0.9.0",
diff --git a/composer.lock b/composer.lock
index f58b160..bc06f33 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,35 +4,35 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "f5d5c19c36f856c3d336c36a43aa23e4",
+ "content-hash": "3412dd2a403927b829237ae4db36351a",
"packages": [
{
"name": "asm89/stack-cors",
- "version": "v2.0.5",
+ "version": "v2.1.1",
"source": {
"type": "git",
"url": "https://github.com/asm89/stack-cors.git",
- "reference": "7a198ec737e926eab15d29368fc6fff66772b0e2"
+ "reference": "73e5b88775c64ccc0b84fb60836b30dc9d92ac4a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/asm89/stack-cors/zipball/7a198ec737e926eab15d29368fc6fff66772b0e2",
- "reference": "7a198ec737e926eab15d29368fc6fff66772b0e2",
+ "url": "https://api.github.com/repos/asm89/stack-cors/zipball/73e5b88775c64ccc0b84fb60836b30dc9d92ac4a",
+ "reference": "73e5b88775c64ccc0b84fb60836b30dc9d92ac4a",
"shasum": ""
},
"require": {
- "php": "^7.0|^8.0",
- "symfony/http-foundation": "~2.7|~3.0|~4.0|~5.0|~6.0",
- "symfony/http-kernel": "~2.7|~3.0|~4.0|~5.0|~6.0"
+ "php": "^7.2|^8.0",
+ "symfony/http-foundation": "^4|^5|^6",
+ "symfony/http-kernel": "^4|^5|^6"
},
"require-dev": {
- "phpunit/phpunit": "^6|^7|^8|^9",
+ "phpunit/phpunit": "^7|^9",
"squizlabs/php_codesniffer": "^3.5"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.0-dev"
+ "dev-master": "2.1-dev"
}
},
"autoload": {
@@ -58,9 +58,9 @@
],
"support": {
"issues": "https://github.com/asm89/stack-cors/issues",
- "source": "https://github.com/asm89/stack-cors/tree/v2.0.5"
+ "source": "https://github.com/asm89/stack-cors/tree/v2.1.1"
},
- "time": "2022-01-03T15:27:13+00:00"
+ "time": "2022-01-18T09:12:03+00:00"
},
{
"name": "brick/math",
@@ -366,29 +366,29 @@
},
{
"name": "dragonmantank/cron-expression",
- "version": "v3.2.4",
+ "version": "v3.3.0",
"source": {
"type": "git",
"url": "https://github.com/dragonmantank/cron-expression.git",
- "reference": "9545dea2a1d92b60c8b3d06f02025c83e999bde0"
+ "reference": "63f2a76a045bac6ec93cc2daf2b534b412aa0313"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/9545dea2a1d92b60c8b3d06f02025c83e999bde0",
- "reference": "9545dea2a1d92b60c8b3d06f02025c83e999bde0",
+ "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/63f2a76a045bac6ec93cc2daf2b534b412aa0313",
+ "reference": "63f2a76a045bac6ec93cc2daf2b534b412aa0313",
"shasum": ""
},
"require": {
"php": "^7.2|^8.0",
- "webmozart/assert": "^1.7.0"
+ "webmozart/assert": "^1.0"
},
"replace": {
"mtdowling/cron-expression": "^1.0"
},
"require-dev": {
"phpstan/extension-installer": "^1.0",
- "phpstan/phpstan": "^0.12",
- "phpstan/phpstan-webmozart-assert": "^0.12.7",
+ "phpstan/phpstan": "^1.0",
+ "phpstan/phpstan-webmozart-assert": "^1.0",
"phpunit/phpunit": "^7.0|^8.0|^9.0"
},
"type": "library",
@@ -415,7 +415,7 @@
],
"support": {
"issues": "https://github.com/dragonmantank/cron-expression/issues",
- "source": "https://github.com/dragonmantank/cron-expression/tree/v3.2.4"
+ "source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.0"
},
"funding": [
{
@@ -423,7 +423,7 @@
"type": "github"
}
],
- "time": "2022-01-13T04:09:37+00:00"
+ "time": "2022-01-14T16:02:05+00:00"
},
{
"name": "egulias/email-validator",
@@ -961,16 +961,16 @@
},
{
"name": "inertiajs/inertia-laravel",
- "version": "v0.5.2",
+ "version": "v0.5.4",
"source": {
"type": "git",
"url": "https://github.com/inertiajs/inertia-laravel.git",
- "reference": "9c8c4201435aa0c11cb832242cf4c1b01bd8ef32"
+ "reference": "6a050ce04a710ac4809161558ac09fe49f13075e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/inertiajs/inertia-laravel/zipball/9c8c4201435aa0c11cb832242cf4c1b01bd8ef32",
- "reference": "9c8c4201435aa0c11cb832242cf4c1b01bd8ef32",
+ "url": "https://api.github.com/repos/inertiajs/inertia-laravel/zipball/6a050ce04a710ac4809161558ac09fe49f13075e",
+ "reference": "6a050ce04a710ac4809161558ac09fe49f13075e",
"shasum": ""
},
"require": {
@@ -1018,7 +1018,7 @@
],
"support": {
"issues": "https://github.com/inertiajs/inertia-laravel/issues",
- "source": "https://github.com/inertiajs/inertia-laravel/tree/v0.5.2"
+ "source": "https://github.com/inertiajs/inertia-laravel/tree/v0.5.4"
},
"funding": [
{
@@ -1026,7 +1026,91 @@
"type": "github"
}
],
- "time": "2022-01-12T16:18:26+00:00"
+ "time": "2022-01-18T10:59:08+00:00"
+ },
+ {
+ "name": "intervention/image",
+ "version": "2.7.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Intervention/image.git",
+ "reference": "744ebba495319501b873a4e48787759c72e3fb8c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Intervention/image/zipball/744ebba495319501b873a4e48787759c72e3fb8c",
+ "reference": "744ebba495319501b873a4e48787759c72e3fb8c",
+ "shasum": ""
+ },
+ "require": {
+ "ext-fileinfo": "*",
+ "guzzlehttp/psr7": "~1.1 || ^2.0",
+ "php": ">=5.4.0"
+ },
+ "require-dev": {
+ "mockery/mockery": "~0.9.2",
+ "phpunit/phpunit": "^4.8 || ^5.7 || ^7.5.15"
+ },
+ "suggest": {
+ "ext-gd": "to use GD library based image processing.",
+ "ext-imagick": "to use Imagick based image processing.",
+ "intervention/imagecache": "Caching extension for the Intervention Image library"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.4-dev"
+ },
+ "laravel": {
+ "providers": [
+ "Intervention\\Image\\ImageServiceProvider"
+ ],
+ "aliases": {
+ "Image": "Intervention\\Image\\Facades\\Image"
+ }
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Intervention\\Image\\": "src/Intervention/Image"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Oliver Vogel",
+ "email": "oliver@olivervogel.com",
+ "homepage": "http://olivervogel.com/"
+ }
+ ],
+ "description": "Image handling and manipulation library with support for Laravel integration",
+ "homepage": "http://image.intervention.io/",
+ "keywords": [
+ "gd",
+ "image",
+ "imagick",
+ "laravel",
+ "thumbnail",
+ "watermark"
+ ],
+ "support": {
+ "issues": "https://github.com/Intervention/image/issues",
+ "source": "https://github.com/Intervention/image/tree/2.7.1"
+ },
+ "funding": [
+ {
+ "url": "https://www.paypal.me/interventionphp",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/Intervention",
+ "type": "github"
+ }
+ ],
+ "time": "2021-12-16T16:49:26+00:00"
},
{
"name": "laravel/framework",
@@ -1464,6 +1548,169 @@
},
"time": "2022-01-10T08:52:49+00:00"
},
+ {
+ "name": "lasserafn/php-initial-avatar-generator",
+ "version": "4.2.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/LasseRafn/php-initial-avatar-generator.git",
+ "reference": "49d0b10cc8819af831e0f6fb1056a7d5ed9512d0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/LasseRafn/php-initial-avatar-generator/zipball/49d0b10cc8819af831e0f6fb1056a7d5ed9512d0",
+ "reference": "49d0b10cc8819af831e0f6fb1056a7d5ed9512d0",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "intervention/image": "^2.3",
+ "lasserafn/php-initials": "^3.0",
+ "lasserafn/php-string-script-language": "^0.3.0",
+ "meyfa/php-svg": "^0.9.0",
+ "overtrue/pinyin": "^4.0",
+ "php": "^7.0|^7.1|^7.2|^7.3|^7.4|^8.0"
+ },
+ "require-dev": {
+ "doctrine/instantiator": "1.0.*",
+ "phpunit/phpunit": "^6.5",
+ "satooshi/php-coveralls": "^1.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "LasseRafn\\InitialAvatarGenerator\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Lasse Rafn",
+ "email": "lasserafn@gmail.com"
+ }
+ ],
+ "description": "A package to generate avatars with initials for PHP",
+ "keywords": [
+ "Initials",
+ "avatar",
+ "image",
+ "svg"
+ ],
+ "support": {
+ "issues": "https://github.com/LasseRafn/php-initial-avatar-generator/issues",
+ "source": "https://github.com/LasseRafn/php-initial-avatar-generator/tree/4.2.1"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/ui-avatars",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2020-12-24T13:12:12+00:00"
+ },
+ {
+ "name": "lasserafn/php-initials",
+ "version": "3.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/LasseRafn/php-initials.git",
+ "reference": "d287e1542687390eb68de779949bc0adc49e2d52"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/LasseRafn/php-initials/zipball/d287e1542687390eb68de779949bc0adc49e2d52",
+ "reference": "d287e1542687390eb68de779949bc0adc49e2d52",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.6|^7.0|^7.1|^8.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^5.7",
+ "satooshi/php-coveralls": "^1.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "LasseRafn\\Initials\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Lasse Rafn",
+ "email": "lasserafn@gmail.com"
+ }
+ ],
+ "description": "A package to generate initials in PHP",
+ "keywords": [
+ "Initials",
+ "php"
+ ],
+ "support": {
+ "issues": "https://github.com/LasseRafn/php-initials/issues",
+ "source": "https://github.com/LasseRafn/php-initials/tree/3.1"
+ },
+ "time": "2020-12-24T12:25:51+00:00"
+ },
+ {
+ "name": "lasserafn/php-string-script-language",
+ "version": "0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/LasseRafn/php-string-script-language.git",
+ "reference": "49a09d4a5e38c1e59a2656ac05b601d615c7cddb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/LasseRafn/php-string-script-language/zipball/49a09d4a5e38c1e59a2656ac05b601d615c7cddb",
+ "reference": "49a09d4a5e38c1e59a2656ac05b601d615c7cddb",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.6|^7.0|^7.1|^8.0"
+ },
+ "require-dev": {
+ "doctrine/instantiator": "1.0.5",
+ "phpunit/phpunit": "^5.6",
+ "phpunit/phpunit-mock-objects": "3.2.4",
+ "satooshi/php-coveralls": "^1.0",
+ "sebastian/exporter": "^1.2"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "LasseRafn\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Lasse Rafn",
+ "email": "lasserafn@gmail.com"
+ }
+ ],
+ "description": "Detect language/encoding of a string in PHP",
+ "keywords": [
+ "language",
+ "php",
+ "string"
+ ],
+ "support": {
+ "issues": "https://github.com/LasseRafn/php-string-script-language/issues",
+ "source": "https://github.com/LasseRafn/php-string-script-language/tree/0.3"
+ },
+ "time": "2020-12-24T12:43:59+00:00"
+ },
{
"name": "league/commonmark",
"version": "2.1.1",
@@ -1875,6 +2122,56 @@
},
"time": "2021-08-15T23:05:49+00:00"
},
+ {
+ "name": "meyfa/php-svg",
+ "version": "v0.9.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/meyfa/php-svg.git",
+ "reference": "34401edef1f724898f468f71b85505fbcc8351bb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/meyfa/php-svg/zipball/34401edef1f724898f468f71b85505fbcc8351bb",
+ "reference": "34401edef1f724898f468f71b85505fbcc8351bb",
+ "shasum": ""
+ },
+ "require": {
+ "ext-gd": "*",
+ "ext-simplexml": "*",
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "meyfa/phpunit-assert-gd": "^1.1",
+ "phpunit/phpunit": "^4.8"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "SVG\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabian Meyer",
+ "homepage": "http://meyfa.net"
+ }
+ ],
+ "description": "Read, edit, write, and render SVG files with PHP",
+ "homepage": "https://github.com/meyfa/php-svg",
+ "keywords": [
+ "svg"
+ ],
+ "support": {
+ "issues": "https://github.com/meyfa/php-svg/issues",
+ "source": "https://github.com/meyfa/php-svg/tree/v0.9.1"
+ },
+ "time": "2019-07-30T18:41:25+00:00"
+ },
{
"name": "monolog/monolog",
"version": "2.3.5",
@@ -2338,6 +2635,79 @@
},
"time": "2021-04-09T13:42:10+00:00"
},
+ {
+ "name": "overtrue/pinyin",
+ "version": "4.0.8",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/overtrue/pinyin.git",
+ "reference": "04bdb4d33d50e8fb1aa5a824064c5151c4b15dc2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/overtrue/pinyin/zipball/04bdb4d33d50e8fb1aa5a824064c5151c4b15dc2",
+ "reference": "04bdb4d33d50e8fb1aa5a824064c5151c4b15dc2",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "require-dev": {
+ "brainmaestro/composer-git-hooks": "^2.7",
+ "friendsofphp/php-cs-fixer": "^2.16",
+ "phpunit/phpunit": "~8.0"
+ },
+ "type": "library",
+ "extra": {
+ "hooks": {
+ "pre-commit": [
+ "composer test",
+ "composer fix-style"
+ ],
+ "pre-push": [
+ "composer test",
+ "composer check-style"
+ ]
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Overtrue\\Pinyin\\": "src/"
+ },
+ "files": [
+ "src/const.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "overtrue",
+ "email": "anzhengchao@gmail.com",
+ "homepage": "http://github.com/overtrue"
+ }
+ ],
+ "description": "Chinese to pinyin translator.",
+ "homepage": "https://github.com/overtrue/pinyin",
+ "keywords": [
+ "Chinese",
+ "Pinyin",
+ "cn2pinyin"
+ ],
+ "support": {
+ "issues": "https://github.com/overtrue/pinyin/issues",
+ "source": "https://github.com/overtrue/pinyin/tree/4.0.8"
+ },
+ "funding": [
+ {
+ "url": "https://www.patreon.com/overtrue",
+ "type": "patreon"
+ }
+ ],
+ "time": "2021-07-19T03:43:32+00:00"
+ },
{
"name": "phpoption/phpoption",
"version": "1.8.1",
diff --git a/config/colors.php b/config/colors.php
new file mode 100644
index 0000000..0b8a3ad
--- /dev/null
+++ b/config/colors.php
@@ -0,0 +1,21 @@
+ [
public_path("storage") => storage_path("app/public"),
+ public_path("avatars") => storage_path("app/avatars"),
],
];
diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php
index 4ddc304..b6cf77f 100644
--- a/database/factories/UserFactory.php
+++ b/database/factories/UserFactory.php
@@ -6,14 +6,17 @@ namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
+use Toby\Enums\EmploymentForm;
class UserFactory extends Factory
{
public function definition(): array
{
return [
- "name" => $this->faker->name(),
+ "name" => "{$this->faker->firstName} {$this->faker->lastName}",
"email" => $this->faker->unique()->safeEmail(),
+ "employment_form" => $this->faker->randomElement(EmploymentForm::cases()),
+ "employment_date" => $this->faker->dateTimeBetween("2020-10-27"),
"remember_token" => Str::random(10),
];
}
diff --git a/database/migrations/2014_10_12_000000_create_users_table.php b/database/migrations/2014_10_12_000000_create_users_table.php
index d1943d9..e7717b5 100644
--- a/database/migrations/2014_10_12_000000_create_users_table.php
+++ b/database/migrations/2014_10_12_000000_create_users_table.php
@@ -13,7 +13,11 @@ return new class() extends Migration {
$table->id();
$table->string("name");
$table->string("email")->unique();
+ $table->string("avatar")->nullable();
+ $table->string("employment_form");
+ $table->dateTime("employment_date");
$table->rememberToken();
+ $table->softDeletes();
$table->timestamps();
});
}
diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php
index 1649f4a..f11b4c8 100644
--- a/database/seeders/DatabaseSeeder.php
+++ b/database/seeders/DatabaseSeeder.php
@@ -11,6 +11,9 @@ class DatabaseSeeder extends Seeder
{
public function run(): void
{
- User::factory(10)->create();
+ User::factory(35)->create();
+ User::factory([
+ "email" => env("LOCAL_EMAIL_FOR_LOGIN_VIA_GOOGLE"),
+ ])->create();
}
}
diff --git a/package-lock.json b/package-lock.json
index 8cb4e0f..c24807a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,10 +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": {
@@ -4722,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",
@@ -8892,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",
@@ -12982,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",
@@ -15970,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",
diff --git a/package.json b/package.json
index 4ac8b9c..f0212fa 100644
--- a/package.json
+++ b/package.json
@@ -22,10 +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": {
diff --git a/public/avatars b/public/avatars
new file mode 120000
index 0000000..c6a773f
--- /dev/null
+++ b/public/avatars
@@ -0,0 +1 @@
+/application/storage/app/avatars
\ No newline at end of file
diff --git a/resources/css/app.css b/resources/css/app.css
index b5c61c9..0bee166 100644
--- a/resources/css/app.css
+++ b/resources/css/app.css
@@ -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;
+}
diff --git a/resources/js/Pages/Dashboard.vue b/resources/js/Pages/Dashboard.vue
index 605d48d..4eb47d9 100644
--- a/resources/js/Pages/Dashboard.vue
+++ b/resources/js/Pages/Dashboard.vue
@@ -291,7 +291,7 @@ export default {
name: 'Payroll',
href: '#',
iconForeground: 'text-yellow-700',
- iconBackground: 'bg-yellow-50'
+ iconBackground: 'bg-yellow-50',
},
{
icon: ReceiptRefundIcon,
diff --git a/resources/js/Pages/Login.vue b/resources/js/Pages/Login.vue
index e3ba099..4b52501 100644
--- a/resources/js/Pages/Login.vue
+++ b/resources/js/Pages/Login.vue
@@ -80,7 +80,7 @@ export default {
errors: {
type: Object,
default: () => ({oauth: null}),
- }
+ },
},
};
diff --git a/resources/js/Pages/Users/Create.vue b/resources/js/Pages/Users/Create.vue
new file mode 100644
index 0000000..3402b70
--- /dev/null
+++ b/resources/js/Pages/Users/Create.vue
@@ -0,0 +1,206 @@
+
+
+ Tylko dodani użytkownicy będą mogli zalogować się do aplikacji.
+
+ Edytuj dane użytkownika, takie jak e-mail czy formę zatrudnienia.
+
+ Lista użytkowników w organizacji.
+
+ {{ user.name }}
+
+ {{ user.email }}
+
+ Dodaj użytkownika
+
+
+ Edytuj użytkownika
+
+
+ Użytkownicy w organizacji
+
+
+
+
+
+
+
+
+
+ Imię i nazwisko
+
+
+ Rola
+
+
+ Forma zatrudnienia
+
+
+ Data rozpoczęcia
+
+
+
+
+
+
+
+
+
+ {{ user.role }}
+
+
+ {{ user.employmentForm }}
+
+
+ {{ user.employmentDate }}
+
+
+
+
+
+
+
+
+ Brak danych
+
+