diff --git a/Makefile b/Makefile index ef642d79..5a004854 100644 --- a/Makefile +++ b/Makefile @@ -54,6 +54,9 @@ test-specific: fix: @docker compose --file ${DOCKER_COMPOSE_FILE} exec --user "${CURRENT_USER_ID}:${CURRENT_USER_GROUP_ID}" ${DOCKER_COMPOSE_APP_CONTAINER} bash -c 'composer csf' +lintf: + @docker compose --file ${DOCKER_COMPOSE_FILE} exec --user "${CURRENT_USER_ID}:${CURRENT_USER_GROUP_ID}" ${DOCKER_COMPOSE_APP_CONTAINER} bash -c 'npm run lintf' + analyse: @docker compose --file ${DOCKER_COMPOSE_FILE} exec --user "${CURRENT_USER_ID}:${CURRENT_USER_GROUP_ID}" ${DOCKER_COMPOSE_APP_CONTAINER} bash -c 'composer analyse' diff --git a/app/DTO/SchoolDTO.php b/app/DTO/SchoolDTO.php index b383df15..459dd885 100644 --- a/app/DTO/SchoolDTO.php +++ b/app/DTO/SchoolDTO.php @@ -8,6 +8,7 @@ class SchoolDTO { public function __construct( public string $name, + public string $regon, public string $city, public string $street, public string $buildingNumber, @@ -19,6 +20,7 @@ public static function createFromArray(array $data): self { $member = new self( $data["nazwa"], + $data["regon"], $data["miejscowosc"], $data["ulica"], $data["numerBudynku"], @@ -28,4 +30,17 @@ public static function createFromArray(array $data): self return $member; } + + public function toArray(): array + { + return [ + "name" => $this->name, + "regon" => $this->regon, + "city" => $this->city, + "street" => $this->street, + "building_number" => $this->buildingNumber, + "apartment_number" => $this->apartmentNumber, + "zip_code" => $this->zipCode, + ]; + } } diff --git a/app/Helpers/RegonHelper.php b/app/Helpers/RegonHelper.php new file mode 100644 index 00000000..9235e888 --- /dev/null +++ b/app/Helpers/RegonHelper.php @@ -0,0 +1,58 @@ + $number + * @param array $wages + */ + public static function calculateChecksum(array $number, array $wages): int + { + $sum = 0; + + for ($i = 0; $i < count($wages); $i++) { + $sum += $wages[$i] * intval($number[$i]); + } + + $checksum = $sum % 11; + + if ($checksum === 10) { + return 0; + } + + return $checksum; + } +} diff --git a/app/Helpers/SortHelper.php b/app/Helpers/SortHelper.php new file mode 100644 index 00000000..a58abc23 --- /dev/null +++ b/app/Helpers/SortHelper.php @@ -0,0 +1,70 @@ + $allowedFields + * @param array $ignoredFields + */ + public function sort(Builder $query, array $allowedFields, array $ignoredFields): Builder + { + [$field, $order] = $this->getSortParameters(); + + if (!in_array($field, $allowedFields, true)) { + if (in_array($field, $ignoredFields, true)) { + return $query; + } + + abort(Status::HTTP_BAD_REQUEST, Lang::get("validation.custom.sorting.unsupported_field", ["attribute" => $field])); + } + + return $query->orderBy($field, $order); + } + + /** + * @return array + */ + public function getSortParameters(): array + { + $field = $this->request->query("sort", "id"); + $ascending = $this->request->query("order", "asc") === "asc"; + + return [$field, $ascending ? "asc" : "desc"]; + } + + public function search(Builder $query, string $field): Builder + { + $searchText = $this->request->query("search"); + + if ($searchText) { + return $query->where($field, "ilike", "%$searchText%"); + } + + return $query; + } + + public function paginate(Builder $query): LengthAwarePaginator + { + $limit = (int)$this->request->query("limit", "50"); + + if (!$limit || $limit < 0) { + $limit = 50; + } + + return $query->paginate($limit); + } +} diff --git a/app/Http/Controllers/QuizController.php b/app/Http/Controllers/QuizController.php index a3206301..f0d42ac9 100644 --- a/app/Http/Controllers/QuizController.php +++ b/app/Http/Controllers/QuizController.php @@ -4,12 +4,14 @@ namespace App\Http\Controllers; +use App\Helpers\SortHelper; use App\Http\Requests\QuizRequest; use App\Http\Requests\UpdateQuizRequest; use App\Http\Resources\QuizResource; use App\Models\Quiz; use App\Services\QuizUpdateService; use Carbon\Carbon; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Inertia\Inertia; @@ -19,11 +21,12 @@ class QuizController extends Controller { - public function index(): Response + public function index(Request $request, SortHelper $sorter): Response { - $quizzes = Quiz::query() - ->with("questions.answers") - ->get(); + $query = $sorter->sort(Quiz::query()->with("questions.answers"), ["id", "title", "updated_at", "created_at"], []); + $query = $this->filterArchivedQuizzes($query, $request); + $query = $sorter->search($query, "title"); + $quizzes = $sorter->paginate($query); return Inertia::render("Admin/Quizzes", ["quizzes" => QuizResource::collection($quizzes)]); } @@ -104,4 +107,15 @@ public function assign(Request $request, Quiz $quiz): RedirectResponse ->back() ->with("status", "Przypisano do testu"); } + + private function filterArchivedQuizzes(Builder $query, Request $request): Builder + { + $showArchived = $request->query("archived", "false") === "true"; + + if (!$showArchived) { + return $query->whereNull("locked_at")->orWhereDate("scheduled_at", ">", Carbon::now()); + } + + return $query; + } } diff --git a/app/Http/Controllers/SchoolsController.php b/app/Http/Controllers/SchoolsController.php index 9f7ae7b1..999bd1cb 100644 --- a/app/Http/Controllers/SchoolsController.php +++ b/app/Http/Controllers/SchoolsController.php @@ -5,11 +5,13 @@ namespace App\Http\Controllers; use App\Enums\Voivodeship; +use App\Helpers\SortHelper; use App\Http\Requests\SchoolRequest; use App\Http\Resources\SchoolResource; use App\Jobs\FetchSchoolsJob; use App\Models\School; use Illuminate\Bus\Batch; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Http\JsonResponse; use Illuminate\Http\RedirectResponse; use Illuminate\Support\Facades\Bus; @@ -24,9 +26,15 @@ class SchoolsController extends Controller { - public function index(): Response + public function index(SortHelper $sorter): Response { - return Inertia::render("Admin/SchoolsPanel", ["schools" => SchoolResource::collection(School::all())]); + $query = $sorter->sort(School::query(), ["id", "name", "regon", "updated_at", "created_at"], ["students", "address"]); + $query = $this->sortByStudents($query, $sorter); + $query = $this->sortByAddress($query, $sorter); + $query = $sorter->search($query, "name"); + $schools = $sorter->paginate($query); + + return Inertia::render("Admin/SchoolsPanel", ["schools" => SchoolResource::collection($schools)]); } public function store(SchoolRequest $request): RedirectResponse @@ -34,7 +42,8 @@ public function store(SchoolRequest $request): RedirectResponse School::query()->create($request->validated()); return redirect() - ->back(); + ->back() + ->with("status", "Szkoła została dodana."); } public function update(SchoolRequest $request, School $school): RedirectResponse @@ -67,6 +76,7 @@ public function fetch(): JsonResponse $jobs = $voivodeships->map(fn(Voivodeship $voivodeships): FetchSchoolsJob => new FetchSchoolsJob($voivodeships, $schoolTypes)); $batch = Bus::batch($jobs)->finally(fn(): bool => Cache::delete("fetch_schools"))->dispatch(); Cache::set("fetch_schools", $batch->id); + Cache::forget("fetched_schools"); return response()->json(["message" => "Pobieranie rozpoczęte"], Status::HTTP_OK); } @@ -75,6 +85,7 @@ public function status(): JsonResponse { return response()->json([ "done" => !$this->isFetching(), + "count" => (int)Cache::get("fetched_schools"), ]); } @@ -95,4 +106,29 @@ protected function findBatch(): ?Batch return Bus::findBatch($batchId); } + + private function sortByStudents(Builder $query, SortHelper $sorter): Builder + { + [$field, $order] = $sorter->getSortParameters(); + + if ($field === "students") { + return $query->withCount("users")->orderBy("users_count", $order); + } + + return $query; + } + + private function sortByAddress(Builder $query, SortHelper $sorter): Builder + { + [$field, $order] = $sorter->getSortParameters(); + + if ($field === "address") { + return $query->orderBy("city", $order) + ->orderBy("zip_code", $order) + ->orderBy("street", $order) + ->orderBy("name", $order); + } + + return $query; + } } diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 6a1c635d..328a9322 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -50,7 +50,7 @@ public function anonymize(User $user): RedirectResponse { $this->authorize("anonymize", $user); $user->update([ - "name" => "Anonymous", + "firstname" => "Anonymous", "surname" => "User", "email" => "anonymous" . $user->id . "@email", "is_anonymized" => true, diff --git a/app/Http/Requests/Auth/RegisterUserRequest.php b/app/Http/Requests/Auth/RegisterUserRequest.php index 4495fc06..d9aacfb8 100644 --- a/app/Http/Requests/Auth/RegisterUserRequest.php +++ b/app/Http/Requests/Auth/RegisterUserRequest.php @@ -17,7 +17,7 @@ public function rules(): array { return [ "email" => ["required", "string", "email:rfc,dns", "max:255"], - "name" => ["required", "string", "max:255"], + "firstname" => ["required", "string", "max:255"], "surname" => ["required", "string", "max:255"], "password" => ["required", "string", "min:8"], "school_id" => ["required", "integer", "exists:schools,id"], diff --git a/app/Http/Requests/QuizRequest.php b/app/Http/Requests/QuizRequest.php index 35918158..716abe07 100644 --- a/app/Http/Requests/QuizRequest.php +++ b/app/Http/Requests/QuizRequest.php @@ -27,7 +27,7 @@ public function prepareForValidation(): void public function rules(): array { return [ - "title" => ["required", "string"], + "title" => ["required", "string", "max:255"], "scheduled_at" => ["date", "after:now"], "duration" => ["numeric", "min:1", "max:2147483647"], ]; diff --git a/app/Http/Requests/SchoolRequest.php b/app/Http/Requests/SchoolRequest.php index 1c44b3b9..fff205fa 100644 --- a/app/Http/Requests/SchoolRequest.php +++ b/app/Http/Requests/SchoolRequest.php @@ -4,6 +4,7 @@ namespace App\Http\Requests; +use App\Rules\Regon; use Illuminate\Contracts\Validation\ValidationRule; use Illuminate\Foundation\Http\FormRequest; @@ -14,18 +15,34 @@ public function authorize(): bool return true; } + public function prepareForValidation(): void + { + if ($this->has("buildingNumber")) { + $this->merge(["building_number" => $this->input("buildingNumber")]); + } + + if ($this->has("apartmentNumber")) { + $this->merge(["apartment_number" => $this->input("apartmentNumber")]); + } + + if ($this->has("zipCode")) { + $this->merge(["zip_code" => $this->input("zipCode")]); + } + } + /** * @return array */ public function rules(): array { return [ - "name" => ["required", "string"], - "city" => ["required", "string"], - "street" => ["required", "string"], - "building_number" => ["required", "string"], - "apartment_number" => ["string"], - "zip_code" => ["required", "string"], + "name" => ["required", "string", "max:255"], + "city" => ["required", "string", "max:255"], + "regon" => ["required", "string", new Regon()], + "street" => ["required", "string", "max:255"], + "building_number" => ["required", "string", "max:255"], + "apartment_number" => ["string", "nullable", "max:255"], + "zip_code" => ["required", "string", "regex:/^\d{2}-\d{3}$/"], ]; } } diff --git a/app/Http/Requests/UpdateQuizRequest.php b/app/Http/Requests/UpdateQuizRequest.php index 2f6e89f2..ac40815a 100644 --- a/app/Http/Requests/UpdateQuizRequest.php +++ b/app/Http/Requests/UpdateQuizRequest.php @@ -28,7 +28,7 @@ public function prepareForValidation(): void public function rules(): array { return [ - "title" => ["required", "string"], + "title" => ["required", "string", "max:255"], "scheduled_at" => ["date", "after:now"], "duration" => ["integer", "min:1", "max:2147483647"], "questions" => ["array"], diff --git a/app/Http/Requests/UserRequest.php b/app/Http/Requests/UserRequest.php index b97c3d16..1ee2b303 100644 --- a/app/Http/Requests/UserRequest.php +++ b/app/Http/Requests/UserRequest.php @@ -17,7 +17,7 @@ public function rules(): array { return [ "email" => ["required", "string", "email", "max:255", "unique:users,email," . $this->user->id], - "name" => ["required", "string", "max:255"], + "firstname" => ["required", "string", "max:255"], "surname" => ["required", "string", "max:255"], "school_id" => ["required", "integer", "exists:schools,id"], ]; diff --git a/app/Http/Resources/RankingResource.php b/app/Http/Resources/RankingResource.php index 6d6dd84e..3d1fcd8d 100644 --- a/app/Http/Resources/RankingResource.php +++ b/app/Http/Resources/RankingResource.php @@ -19,7 +19,7 @@ public function toArray(Request $request): array return [ "user" => [ "id" => $this->user->id, - "name" => $isAdmin ? $this->user->name : null, + "firstname" => $isAdmin ? $this->user->firstname : null, "surname" => $isAdmin ? $this->user->surname : null, "school" => $this->user->school, ], diff --git a/app/Http/Resources/SchoolResource.php b/app/Http/Resources/SchoolResource.php index 5909daa3..eee4b506 100644 --- a/app/Http/Resources/SchoolResource.php +++ b/app/Http/Resources/SchoolResource.php @@ -17,7 +17,15 @@ public function toArray(Request $request): array return [ "id" => $this->id, "name" => $this->name, + "regon" => $this->regon, "city" => $this->city, + "street" => $this->street, + "buildingNumber" => $this->building_number, + "apartmentNumber" => $this->apartment_number, + "zipCode" => $this->zip_code, + "numberOfStudents" => $this->users()->count(), + "createdAt" => $this->created_at, + "updatedAt" => $this->updated_at, ]; } } diff --git a/app/Http/Resources/UserResource.php b/app/Http/Resources/UserResource.php index 941162c2..10bde42c 100644 --- a/app/Http/Resources/UserResource.php +++ b/app/Http/Resources/UserResource.php @@ -16,7 +16,7 @@ public function toArray(Request $request): array { return [ "id" => $this->id, - "name" => $this->name, + "firstname" => $this->firstname, "surname" => $this->surname, "email" => $this->email, "school" => SchoolResource::make($this->school), diff --git a/app/Jobs/FetchSchoolsJob.php b/app/Jobs/FetchSchoolsJob.php index 1ddef93f..4c37e676 100644 --- a/app/Jobs/FetchSchoolsJob.php +++ b/app/Jobs/FetchSchoolsJob.php @@ -10,6 +10,7 @@ use Illuminate\Bus\Batchable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Queue\Queueable; +use Illuminate\Support\Facades\Cache; class FetchSchoolsJob implements ShouldQueue { @@ -26,6 +27,7 @@ public function __construct( public function handle(GetSchoolDataService $service): void { - $service->getSchools($this->voivodeship, $this->schoolTypes); + $added_schools = $service->getSchools($this->voivodeship, $this->schoolTypes); + Cache::set("fetched_schools", $added_schools); } } diff --git a/app/Models/Quiz.php b/app/Models/Quiz.php index 18b73ebf..87d4bdd2 100644 --- a/app/Models/Quiz.php +++ b/app/Models/Quiz.php @@ -18,8 +18,8 @@ * @property string $title * @property Carbon $created_at * @property Carbon $updated_at - * @property Carbon $scheduled_at - * @property Carbon $ranking_published_at + * @property ?Carbon $scheduled_at + * @property ?Carbon $ranking_published_at * @property ?Carbon $locked_at * @property ?int $duration * @property bool $isLocked diff --git a/app/Models/School.php b/app/Models/School.php index 3524f74e..7c357a54 100644 --- a/app/Models/School.php +++ b/app/Models/School.php @@ -5,11 +5,14 @@ namespace App\Models; use Carbon\Carbon; +use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\HasMany; /** * @property int $id + * @property string $regon * @property string $name * @property string $city * @property string $street @@ -18,6 +21,7 @@ * @property string $zip_code * @property Carbon $created_at * @property Carbon $updated_at + * @property Collection $users */ class School extends Model { @@ -25,10 +29,16 @@ class School extends Model protected $fillable = [ "name", + "regon", "city", "street", "building_number", "apartment_number", "zip_code", ]; + + public function users(): HasMany + { + return $this->hasMany(User::class); + } } diff --git a/app/Models/User.php b/app/Models/User.php index d31b618a..32ac52d4 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -20,7 +20,7 @@ /** * @param string $token * @property int $id - * @property string $name + * @property string $firstname * @property string $surname * @property string $email * @property string $password @@ -40,7 +40,7 @@ class User extends Authenticatable implements MustVerifyEmail, CanResetPassword use HasRoles; protected $fillable = [ - "name", + "firstname", "surname", "email", "school_id", diff --git a/app/Rules/Regon.php b/app/Rules/Regon.php new file mode 100644 index 00000000..b2899558 --- /dev/null +++ b/app/Rules/Regon.php @@ -0,0 +1,60 @@ +validate_short_regon($value, $fail); + + if (strlen($value) === 14) { + $this->validate_long_regon($value, $fail); + } + } + + protected function validate_short_regon(string $value, Closure $fail): void + { + $digits = str_split($value); + $checksum = RegonHelper::calculateChecksum($digits, RegonHelper::WEIGHTS_SHORT) % 11; + + if ($checksum !== intval($digits[8])) { + $fail(Lang::get("validation.custom.regon.invalid_checksum")); + } + } + + protected function validate_long_regon(string $value, Closure $fail): void + { + $digits = str_split($value); + + $checksum = RegonHelper::calculateChecksum($digits, RegonHelper::WEIGHTS_LONG) % 11; + + if ($checksum !== intval($digits[13])) { + $fail(Lang::get("validation.custom.regon.invalid_checksum")); + } + } +} diff --git a/app/Services/GetSchoolDataService.php b/app/Services/GetSchoolDataService.php index 0575eef5..f3f0761c 100644 --- a/app/Services/GetSchoolDataService.php +++ b/app/Services/GetSchoolDataService.php @@ -21,9 +21,9 @@ public function __construct( /** * @param array $schoolTypes */ - public function getSchools(Voivodeship $voivodeship, array $schoolTypes): void + public function getSchools(Voivodeship $voivodeship, array $schoolTypes): int { - $this->store($this->fetchSchools($voivodeship, $schoolTypes)); + return $this->store($this->fetchSchools($voivodeship, $schoolTypes)); } /** @@ -45,17 +45,17 @@ protected function fetchSchools(Voivodeship $voivodeship, array $schoolTypes): C /** * @param Collection $schools */ - protected function store(Collection $schools): void + protected function store(Collection $schools): int { - foreach ($schools as $school) { - School::firstOrCreate([ - "name" => $school->name, - "city" => $school->city, - "street" => $school->street, - "building_number" => $school->buildingNumber, - "apartment_number" => $school->apartmentNumber, - "zip_code" => $school->zipCode, - ]); + $fetched = 0; + + foreach ($schools as $dto) { + if (School::query()->where("regon", "=", $dto->regon)->doesntExist()) { + School::query()->create($dto->toArray()); + ++$fetched; + } } + + return $fetched; } } diff --git a/database/factories/SchoolFactory.php b/database/factories/SchoolFactory.php index bbbd7a75..0d121b9c 100644 --- a/database/factories/SchoolFactory.php +++ b/database/factories/SchoolFactory.php @@ -4,6 +4,7 @@ namespace Database\Factories; +use App\Helpers\RegonHelper; use App\Models\School; use Illuminate\Database\Eloquent\Factories\Factory; @@ -21,11 +22,12 @@ public function definition(): array { return [ "name" => fake()->company(), + "regon" => RegonHelper::generateShortRegon(), "city" => fake()->city(), "street" => fake()->streetName(), "building_number" => fake()->buildingNumber(), "apartment_number" => fake()->buildingNumber(), - "zip_code" => fake()->postcode(), + "zip_code" => fake()->randomNumber(2) . "-" . fake()->randomNumber(3), ]; } diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index 6c18b01e..15ac6060 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -19,7 +19,7 @@ class UserFactory extends Factory public function definition(): array { return [ - "name" => fake()->firstName(), + "firstname" => fake()->firstName(), "surname" => fake()->lastName(), "email" => fake()->unique()->safeEmail(), "email_verified_at" => Carbon::now(), diff --git a/database/migrations/0001_01_01_000000_create_users_table.php b/database/migrations/0001_01_01_000000_create_users_table.php index 38b52a4a..5f34af2f 100644 --- a/database/migrations/0001_01_01_000000_create_users_table.php +++ b/database/migrations/0001_01_01_000000_create_users_table.php @@ -11,7 +11,7 @@ public function up(): void { Schema::create("users", function (Blueprint $table): void { $table->bigIncrements("id")->unique(); - $table->string("name"); + $table->string("firstname"); $table->string("surname"); $table->string("email")->unique(); $table->timestamp("email_verified_at")->nullable(); diff --git a/database/migrations/2024_08_08_113859_create_schools_table.php b/database/migrations/2024_08_08_113859_create_schools_table.php index 1178a14b..67d89e7f 100644 --- a/database/migrations/2024_08_08_113859_create_schools_table.php +++ b/database/migrations/2024_08_08_113859_create_schools_table.php @@ -11,6 +11,7 @@ public function up(): void { Schema::create("schools", function (Blueprint $table): void { $table->bigIncrements("id")->unique(); + $table->string("regon"); $table->string("name"); $table->string("city"); $table->string("street"); diff --git a/database/seeders/AdminSeeder.php b/database/seeders/AdminSeeder.php index ccec082c..44cea50a 100644 --- a/database/seeders/AdminSeeder.php +++ b/database/seeders/AdminSeeder.php @@ -18,7 +18,7 @@ public function run(): void $superAdmin = User::firstOrCreate( ["email" => "superadmin@example.com"], [ - "name" => "Example", + "firstname" => "Example", "surname" => "Super Admin", "email_verified_at" => Carbon::now(), "password" => Hash::make("password"), @@ -31,7 +31,7 @@ public function run(): void $admin = User::firstOrCreate( ["email" => "admin@example.com"], [ - "name" => "Example", + "firstname" => "Example", "surname" => "Admin", "email_verified_at" => Carbon::now(), "password" => Hash::make("password"), @@ -44,7 +44,7 @@ public function run(): void $user = User::firstOrCreate( ["email" => "user@example.com"], [ - "name" => "Example", + "firstname" => "Example", "surname" => "User", "email_verified_at" => Carbon::now(), "password" => Hash::make("password"), diff --git a/lang/en/validation.php b/lang/en/validation.php index a9fb9422..90d6575f 100644 --- a/lang/en/validation.php +++ b/lang/en/validation.php @@ -154,6 +154,11 @@ "attribute-name" => [ "rule-name" => "custom-message", ], + "regon" => [ + "digits_only" => "The :attribute must contain only digits.", + "invalid_length" => "The :attribute must be 9 or 14 digits long.", + "invalid_checksum" => "The :attribute checksum is incorrect for a valid REGON.", + ], ], "attributes" => [], ]; diff --git a/lang/pl/validation.php b/lang/pl/validation.php index c690cb35..0ebd5cde 100644 --- a/lang/pl/validation.php +++ b/lang/pl/validation.php @@ -131,9 +131,18 @@ "questions.*.text" => [ "required" => "Treść pytania jest wymagana.", ], + "regon" => [ + "digits_only" => "Pole :attribute może zawierać tylko cyfry.", + "invalid_length" => "Pole :attribute musi mieć dokładnie 9 lub 14 cyfr.", + "invalid_checksum" => "Pole :attribute ma nieprawidłową sumę kontrolną.", + ], + "sorting" => [ + "unsupported_field" => "Sortowanie po polu :attribute nie jest wspierane.", + ], ], "attributes" => [ - "name" => "imię", + "name" => "nazwa", + "firstname" => "imię", "title" => "tytuł", "duration" => "czas trwania", "scheduled_at" => "rozpoczęcie", @@ -142,5 +151,11 @@ "date" => "data", "password" => "hasło", "school_id" => "szkoła", + "regon" => "regon", + "street" => "ulica", + "building_number" => "numer budynku", + "apartment_number" => "numer mieszkania", + "zip_code" => "kod pocztowy", + "city" => "miasto", ], ]; diff --git a/resources/js/Helpers/Params.ts b/resources/js/Helpers/Params.ts new file mode 100644 index 00000000..7483c8c3 --- /dev/null +++ b/resources/js/Helpers/Params.ts @@ -0,0 +1,10 @@ +export function useParams(): Record { + const searchParams = new URL(window.location.href).searchParams + let params: Record = {} + + for (const [key, value] of searchParams.entries()) { + params[key] = value + } + + return params +} diff --git a/resources/js/Helpers/Sorter.ts b/resources/js/Helpers/Sorter.ts new file mode 100644 index 00000000..61d3679d --- /dev/null +++ b/resources/js/Helpers/Sorter.ts @@ -0,0 +1,43 @@ +import {computed, type Ref, ref, watch} from 'vue' +import {router} from '@inertiajs/vue3' +import {useParams} from '@/Helpers/Params' + +export function useSorter(sortOptions: SortOption[], searchText?: Ref, customQueries?: () => string[]): [query: Ref, Ref] { + const params = useParams() + const key = ref(params.sort) + const desc = ref(params.order) + + const options = computed(() => sortOptions.map