From b177467a26d081af34be0467eea564c54699e4e3 Mon Sep 17 00:00:00 2001 From: mblajek Date: Sat, 16 Dec 2023 14:51:18 +0100 Subject: [PATCH 1/3] FZ-117-118 add base tqueries for clients and staff, fix permissions --- .../Facility/ClientTqueryController.php | 53 +++++++++++++++++++ .../Facility/MeetingTqueryController.php | 2 +- .../Facility/StaffTqueryController.php | 53 +++++++++++++++++++ app/Tquery/Config/TqDataTypeEnum.php | 1 - app/Tquery/Config/TqTableAliasEnum.php | 6 ++- app/Tquery/Engine/TqBuilder.php | 6 ++- app/Tquery/Tables/ClientTquery.php | 25 +++++++++ app/Tquery/Tables/StaffTquery.php | 25 +++++++++ routes/api.php | 13 +++++ 9 files changed, 178 insertions(+), 6 deletions(-) create mode 100644 app/Http/Controllers/Facility/ClientTqueryController.php create mode 100644 app/Http/Controllers/Facility/StaffTqueryController.php create mode 100644 app/Tquery/Tables/ClientTquery.php create mode 100644 app/Tquery/Tables/StaffTquery.php diff --git a/app/Http/Controllers/Facility/ClientTqueryController.php b/app/Http/Controllers/Facility/ClientTqueryController.php new file mode 100644 index 000000000..b45d88af1 --- /dev/null +++ b/app/Http/Controllers/Facility/ClientTqueryController.php @@ -0,0 +1,53 @@ +permissionOneOf(Permission::facilityAdmin); + } + + private function getTqService(): TqService + { + return App::make(ClientTquery::class, ['facility' => $this->getFacilityOrFail()]); + } + + #[OpenApiGet( + path: '/api/v1/facility/{facility}/user/client/tquery', + permissions: new PermissionDescribe(Permission::facilityAdmin), + summary: 'Facility clients tquery', + tag: 'Facility client', + parameters: [new FacilityParameter()], + )] + public function get(): JsonResponse + { + return new JsonResponse($this->getTqService()->getConfigArray()); + } + + #[OpenApiPost( + path: '/api/v1/facility/{facility}/user/client/tquery', + permissions: new PermissionDescribe(Permission::facilityAdmin), + summary: 'Facility clients tquery', + tag: 'Facility client', + parameters: [new FacilityParameter()], + )] + public function post( + Request $request, + ): JsonResponse { + return new JsonResponse($this->getTqService()->query($request)); + } +} diff --git a/app/Http/Controllers/Facility/MeetingTqueryController.php b/app/Http/Controllers/Facility/MeetingTqueryController.php index 830bcd0ba..2dbef5278 100644 --- a/app/Http/Controllers/Facility/MeetingTqueryController.php +++ b/app/Http/Controllers/Facility/MeetingTqueryController.php @@ -18,7 +18,7 @@ class MeetingTqueryController extends ApiController { protected function initPermissions(): void { - $this->permissionOneOf(Permission::globalAdmin); + $this->permissionOneOf(Permission::facilityAdmin); } private function getTqService(): TqService diff --git a/app/Http/Controllers/Facility/StaffTqueryController.php b/app/Http/Controllers/Facility/StaffTqueryController.php new file mode 100644 index 000000000..73ccb6861 --- /dev/null +++ b/app/Http/Controllers/Facility/StaffTqueryController.php @@ -0,0 +1,53 @@ +permissionOneOf(Permission::facilityAdmin); + } + + private function getTqService(): TqService + { + return App::make(StaffTquery::class, ['facility' => $this->getFacilityOrFail()]); + } + + #[OpenApiGet( + path: '/api/v1/facility/{facility}/user/staff/tquery', + permissions: new PermissionDescribe(Permission::facilityAdmin), + summary: 'Facility staff tquery', + tag: 'Facility staff', + parameters: [new FacilityParameter()], + )] + public function get(): JsonResponse + { + return new JsonResponse($this->getTqService()->getConfigArray()); + } + + #[OpenApiPost( + path: '/api/v1/facility/{facility}/user/staff/tquery', + permissions: new PermissionDescribe(Permission::facilityAdmin), + summary: 'Facility staff tquery', + tag: 'Facility staff', + parameters: [new FacilityParameter()], + )] + public function post( + Request $request, + ): JsonResponse { + return new JsonResponse($this->getTqService()->query($request)); + } +} diff --git a/app/Tquery/Config/TqDataTypeEnum.php b/app/Tquery/Config/TqDataTypeEnum.php index 2aab10a59..b8a5a0ccb 100644 --- a/app/Tquery/Config/TqDataTypeEnum.php +++ b/app/Tquery/Config/TqDataTypeEnum.php @@ -6,7 +6,6 @@ use App\Rules\Valid; use App\Rules\RegexpIsValidRule; use App\Tquery\Filter\TqFilterOperator; -use App\Utils\Date\DateHelper; enum TqDataTypeEnum { diff --git a/app/Tquery/Config/TqTableAliasEnum.php b/app/Tquery/Config/TqTableAliasEnum.php index 4412d52cb..1059ce844 100644 --- a/app/Tquery/Config/TqTableAliasEnum.php +++ b/app/Tquery/Config/TqTableAliasEnum.php @@ -8,12 +8,14 @@ enum TqTableAliasEnum { case created_by; case last_login_facility; + case members; public function baseTable(): TqTableEnum { return match ($this) { self::created_by => TqTableEnum::users, self::last_login_facility => TqTableEnum::facilities, + self::members => TqTableEnum::members, }; } @@ -21,8 +23,8 @@ public function applyJoin(TqBuilder $builder, TqTableEnum $joinBase, bool $left) { $joinColumn = match ($this) { self::created_by => $this->name, - self::last_login_facility => $this->name . '_id', + default => $this->name . '_id', }; - $builder->join($joinBase, $this, $joinColumn, $left); + $builder->join($joinBase, $this, $joinColumn, $left, false); } } diff --git a/app/Tquery/Engine/TqBuilder.php b/app/Tquery/Engine/TqBuilder.php index 89b5d93c5..37d7c85ae 100644 --- a/app/Tquery/Engine/TqBuilder.php +++ b/app/Tquery/Engine/TqBuilder.php @@ -36,17 +36,19 @@ public function join( TqTableAliasEnum $table, string $joinColumn, bool $left, + bool $inv, ): bool { if (in_array($table, $this->joins, strict: true)) { return false; } + [$tableColumn, $baseColumn] = $inv ? [$joinColumn, 'id'] : ['id', $joinColumn]; $this->joins[] = $table; $tableBase = $table->baseTable(); $this->builder->join( "{$tableBase->name} as {$table->name}", - "{$table->name}.id", + "{$table->name}.$tableColumn", '=', - "{$joinBase->name}.$joinColumn", + "{$joinBase->name}.$baseColumn", $left ? 'left' : 'inner', ); return true; diff --git a/app/Tquery/Tables/ClientTquery.php b/app/Tquery/Tables/ClientTquery.php new file mode 100644 index 000000000..26805ca93 --- /dev/null +++ b/app/Tquery/Tables/ClientTquery.php @@ -0,0 +1,25 @@ +join(TqTableEnum::users, TqTableAliasEnum::members, 'user_id', left: false, inv: true); + $builder->where(fn(string $bind) => "members.facility_id = $bind", false, $this->facility->id, false, false); + $builder->where(fn(null $bind) => 'members.client_id is not null', false, null, false, false); + return $builder; + } +} diff --git a/app/Tquery/Tables/StaffTquery.php b/app/Tquery/Tables/StaffTquery.php new file mode 100644 index 000000000..9b93e53bb --- /dev/null +++ b/app/Tquery/Tables/StaffTquery.php @@ -0,0 +1,25 @@ +join(TqTableEnum::users, TqTableAliasEnum::members, 'user_id', left: false, inv: true); + $builder->where(fn(string $bind) => "members.facility_id = $bind", false, $this->facility->id, false, false); + $builder->where(fn(null $bind) => 'members.staff_member_id is not null', false, null, false, false); + return $builder; + } +} diff --git a/routes/api.php b/routes/api.php index 8e2c95acc..dda802620 100644 --- a/routes/api.php +++ b/routes/api.php @@ -5,8 +5,10 @@ use App\Http\Controllers\Admin\AdminFacilityController; use App\Http\Controllers\Admin\AdminMemberController; use App\Http\Controllers\Admin\AdminUserController; +use App\Http\Controllers\Facility\ClientTqueryController; use App\Http\Controllers\Facility\MeetingController; use App\Http\Controllers\Facility\MeetingTqueryController; +use App\Http\Controllers\Facility\StaffTqueryController; use App\Http\Controllers\MailController; use App\Http\Controllers\SystemController; use App\Http\Controllers\Tquery\AdminFacilityTqueryController; @@ -62,6 +64,17 @@ }); }); Route::prefix('/facility/{facility}')->group(function () { + Route::prefix('/user')->group(function () { + Route::prefix('/client')->group(function () { + Route::get('/tquery', [ClientTqueryController::class, 'get']); + Route::post('/tquery', [ClientTqueryController::class, 'post']); + }); + Route::prefix('/staff')->group(function () { + Route::get('/tquery', [StaffTqueryController::class, 'get']); + Route::post('/tquery', [StaffTqueryController::class, 'post']); + }); + }); + Route::prefix('/meeting')->group(function () { Route::post('/', [MeetingController::class, 'post']); Route::get('/list', [MeetingController::class, 'facilityMeetingList']); From 7c246fbb66f4e406e10a5411c87e1a021bef1ada Mon Sep 17 00:00:00 2001 From: TPReal Date: Sat, 16 Dec 2023 19:55:02 +0100 Subject: [PATCH 2/3] Created the stub of the staff and clients list. --- resources/js/App.tsx | 6 +++-- .../memo-api/groups/FacilityClient.ts | 9 +++++++ .../memo-api/groups/FacilityStaff.ts | 9 +++++++ resources/js/features/root/layout/Navbar.tsx | 10 ++++---- .../features/root/pages/ClientsTable.page.tsx | 24 +++++++++++++++++++ .../features/root/pages/StaffTable.page.tsx | 24 +++++++++++++++++++ resources/lang/pl_PL/models.yml | 4 +++- resources/lang/pl_PL/tables.yml | 20 ++++++++++++++++ 8 files changed, 98 insertions(+), 8 deletions(-) create mode 100644 resources/js/data-access/memo-api/groups/FacilityClient.ts create mode 100644 resources/js/data-access/memo-api/groups/FacilityStaff.ts create mode 100644 resources/js/features/root/pages/ClientsTable.page.tsx create mode 100644 resources/js/features/root/pages/StaffTable.page.tsx diff --git a/resources/js/App.tsx b/resources/js/App.tsx index c9c9576d0..b7547becf 100644 --- a/resources/js/App.tsx +++ b/resources/js/App.tsx @@ -14,8 +14,10 @@ const AdminFacilitiesListPage = lazy(() => import("features/root/pages/AdminFaci const AdminUsersListPage = lazy(() => import("features/root/pages/AdminUsersList.page")); const CalendarPage = lazy(() => import("features/root/pages/Calendar.page")); const CalendarTablePage = lazy(() => import("features/root/pages/CalendarTable.page")); +const ClientsTablePage = lazy(() => import("features/root/pages/ClientsTable.page")); const LoginPage = lazy(() => import("features/authentication/pages/Login.page")); const RootPage = lazy(() => import("features/root/pages/Root.page")); +const StaffTablePage = lazy(() => import("features/root/pages/StaffTable.page")); const App: VoidComponent = () => { const facilitiesQuery = createQuery(System.facilitiesQueryOptions); @@ -53,8 +55,8 @@ const App: VoidComponent = () => { - - + + diff --git a/resources/js/data-access/memo-api/groups/FacilityClient.ts b/resources/js/data-access/memo-api/groups/FacilityClient.ts new file mode 100644 index 000000000..bedffaed9 --- /dev/null +++ b/resources/js/data-access/memo-api/groups/FacilityClient.ts @@ -0,0 +1,9 @@ +/** + * @see {@link https://test-memo.fdds.pl/api/documentation#/Facility%20client production docs} + * @see {@link http://localhost:9081/api/documentation#/Facility%20client local docs} + */ +export namespace FacilityClient { + export const keys = { + client: () => ["client"] as const, + }; +} diff --git a/resources/js/data-access/memo-api/groups/FacilityStaff.ts b/resources/js/data-access/memo-api/groups/FacilityStaff.ts new file mode 100644 index 000000000..f190b7175 --- /dev/null +++ b/resources/js/data-access/memo-api/groups/FacilityStaff.ts @@ -0,0 +1,9 @@ +/** + * @see {@link https://test-memo.fdds.pl/api/documentation#/Facility%20staff production docs} + * @see {@link http://localhost:9081/api/documentation#/Facility%20staff local docs} + */ +export namespace FacilityStaff { + export const keys = { + staff: () => ["staff"] as const, + }; +} diff --git a/resources/js/features/root/layout/Navbar.tsx b/resources/js/features/root/layout/Navbar.tsx index c1c67d384..4c58e5a99 100644 --- a/resources/js/features/root/layout/Navbar.tsx +++ b/resources/js/features/root/layout/Navbar.tsx @@ -91,16 +91,16 @@ function getSectionItems( href: `/${facilityUrl}/admin/calendar`, routeKey: "facility.admin.calendar", }, - { - icon: CLIENT_ICONS.menu, - href: `/${facilityUrl}/admin/clients`, - routeKey: "facility.admin.clients", - }, { icon: STAFF_ICONS.menu, href: `/${facilityUrl}/admin/staff`, routeKey: "facility.admin.staff", }, + { + icon: CLIENT_ICONS.menu, + href: `/${facilityUrl}/admin/clients`, + routeKey: "facility.admin.clients", + }, { icon: HiOutlineClipboardDocumentList, href: `/${facilityUrl}/admin/reports`, diff --git a/resources/js/features/root/pages/ClientsTable.page.tsx b/resources/js/features/root/pages/ClientsTable.page.tsx new file mode 100644 index 000000000..d953b4a92 --- /dev/null +++ b/resources/js/features/root/pages/ClientsTable.page.tsx @@ -0,0 +1,24 @@ +import {createTableTranslations} from "components/ui/Table"; +import {TQueryTable} from "components/ui/Table/TQueryTable"; +import {FacilityClient} from "data-access/memo-api/groups/FacilityClient"; +import {VoidComponent} from "solid-js"; +import {activeFacilityId} from "state/activeFacilityId.state"; + +export default (() => { + return ( + <> + + + ); +}) satisfies VoidComponent; diff --git a/resources/js/features/root/pages/StaffTable.page.tsx b/resources/js/features/root/pages/StaffTable.page.tsx new file mode 100644 index 000000000..704eeed1e --- /dev/null +++ b/resources/js/features/root/pages/StaffTable.page.tsx @@ -0,0 +1,24 @@ +import {createTableTranslations} from "components/ui/Table"; +import {TQueryTable} from "components/ui/Table/TQueryTable"; +import {FacilityStaff} from "data-access/memo-api/groups/FacilityStaff"; +import {VoidComponent} from "solid-js"; +import {activeFacilityId} from "state/activeFacilityId.state"; + +export default (() => { + return ( + <> + + + ); +}) satisfies VoidComponent; diff --git a/resources/lang/pl_PL/models.yml b/resources/lang/pl_PL/models.yml index 86c80683d..d039f27ed 100644 --- a/resources/lang/pl_PL/models.yml +++ b/resources/lang/pl_PL/models.yml @@ -54,11 +54,11 @@ permissions: user: _name: "osoba" _name_plural: "osoby" + name: "imię i nazwisko" email: "$t(models.generic.email)" createdAt: "$t(models.generic.createdAt)" updatedAt: "$t(models.generic.updatedAt)" createdBy: "$t(models.generic.createdBy)" - name: "imię i nazwisko" hasGlobalAdmin: "globalny administrator" passwordExpireAt: "data wygaśnięcia hasła" hasPassword: "posiada hasło" @@ -70,10 +70,12 @@ user: staff: _name: "pracownik" _name_plural: "pracownicy" + name: "$t(models.user.name)" client: _name: "klient" _name_plural: "klienci" + name: "$t(models.user.name)" gender: "$t(dictionary.gender._name)" meeting: diff --git a/resources/lang/pl_PL/tables.yml b/resources/lang/pl_PL/tables.yml index 25db02232..a4ac9c0dd 100644 --- a/resources/lang/pl_PL/tables.yml +++ b/resources/lang/pl_PL/tables.yml @@ -28,6 +28,26 @@ tables: facilities.count: "$t(models.user.facilities.count)" actions: "$t(tables.tables.generic.columnNames.actions)" + staff: + tableName: "$t(models.staff._name_plural)" + summary__zero: "Brak pracowników" + summary__one: "{{count, number}} pracownik" + summary__few: "{{count, number}} pracowników" + summary__many: "{{count, number}} pracowników" + columnNames: + id: "$t(tables.tables.generic.columnNames.id)" + name: "$t(models.staff.name)" + + clients: + tableName: "$t(models.client._name_plural)" + summary__zero: "Brak klientów" + summary__one: "{{count, number}} klient" + summary__few: "{{count, number}} klientów" + summary__many: "{{count, number}} klientów" + columnNames: + id: "$t(tables.tables.generic.columnNames.id)" + name: "$t(models.client.name)" + userFacilities: tableName: "$t(models.user.members)" columnNames: From 2b32f189b830679b5d9f033d1801ae669509f5ac Mon Sep 17 00:00:00 2001 From: TPReal Date: Sun, 17 Dec 2023 20:39:19 +0100 Subject: [PATCH 3/3] Configured some columns for staff and client lists. --- .../features/root/pages/ClientsTable.page.tsx | 4 ++++ .../features/root/pages/StaffTable.page.tsx | 18 +++++++++++++++++- resources/lang/pl_PL/models.yml | 19 +++++++++++++++---- resources/lang/pl_PL/tables.yml | 12 ++++++++++++ 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/resources/js/features/root/pages/ClientsTable.page.tsx b/resources/js/features/root/pages/ClientsTable.page.tsx index d953b4a92..2a101ea15 100644 --- a/resources/js/features/root/pages/ClientsTable.page.tsx +++ b/resources/js/features/root/pages/ClientsTable.page.tsx @@ -16,6 +16,10 @@ export default (() => { columns={[ {name: "id", initialVisible: false}, {name: "name", columnDef: {enableHiding: false}}, + // {name: "genderDictId"}, + {name: "createdAt", columnDef: {sortDescFirst: true}, initialVisible: false}, + {name: "createdBy.name", initialVisible: false}, + {name: "updatedAt", columnDef: {sortDescFirst: true}, initialVisible: false}, ]} initialSort={[{id: "name", desc: false}]} /> diff --git a/resources/js/features/root/pages/StaffTable.page.tsx b/resources/js/features/root/pages/StaffTable.page.tsx index 704eeed1e..72404ac14 100644 --- a/resources/js/features/root/pages/StaffTable.page.tsx +++ b/resources/js/features/root/pages/StaffTable.page.tsx @@ -1,8 +1,9 @@ -import {createTableTranslations} from "components/ui/Table"; +import {cellFunc, createTableTranslations} from "components/ui/Table"; import {TQueryTable} from "components/ui/Table/TQueryTable"; import {FacilityStaff} from "data-access/memo-api/groups/FacilityStaff"; import {VoidComponent} from "solid-js"; import {activeFacilityId} from "state/activeFacilityId.state"; +import {Email} from "components/ui/Email"; export default (() => { return ( @@ -16,6 +17,21 @@ export default (() => { columns={[ {name: "id", initialVisible: false}, {name: "name", columnDef: {enableHiding: false}}, + {name: "email", columnDef: {cell: cellFunc((v) => )}}, + {name: "hasEmailVerified", initialVisible: false}, + {name: "hasPassword"}, + {name: "passwordExpireAt", initialVisible: false}, + { + name: "hasGlobalAdmin", + columnDef: { + cell: cellFunc((adm) => {adm ? "💪🏽" : ""}), + size: 130, + }, + initialVisible: false, + }, + {name: "createdAt", columnDef: {sortDescFirst: true}, initialVisible: false}, + {name: "createdBy.name", initialVisible: false}, + {name: "updatedAt", columnDef: {sortDescFirst: true}, initialVisible: false}, ]} initialSort={[{id: "name", desc: false}]} /> diff --git a/resources/lang/pl_PL/models.yml b/resources/lang/pl_PL/models.yml index d039f27ed..ed9c869c7 100644 --- a/resources/lang/pl_PL/models.yml +++ b/resources/lang/pl_PL/models.yml @@ -56,9 +56,6 @@ user: _name_plural: "osoby" name: "imię i nazwisko" email: "$t(models.generic.email)" - createdAt: "$t(models.generic.createdAt)" - updatedAt: "$t(models.generic.updatedAt)" - createdBy: "$t(models.generic.createdBy)" hasGlobalAdmin: "globalny administrator" passwordExpireAt: "data wygaśnięcia hasła" hasPassword: "posiada hasło" @@ -66,17 +63,31 @@ user: hasEmailVerified: "e-mail zweryfikowany" members: "przypisane placówki" facilities.count: "liczba placówek" + createdAt: "$t(models.generic.createdAt)" + createdBy: "$t(models.generic.createdBy)" + updatedAt: "$t(models.generic.updatedAt)" staff: _name: "pracownik" _name_plural: "pracownicy" name: "$t(models.user.name)" + email: "$t(models.user.email)" + hasEmailVerified: "$t(models.user.hasEmailVerified)" + hasPassword: "$t(models.user.hasPassword)" + passwordExpireAt: "$t(models.user.passwordExpireAt)" + hasGlobalAdmin: "$t(models.user.hasGlobalAdmin)" + createdAt: "$t(models.generic.createdAt)" + createdBy: "$t(models.generic.createdBy)" + updatedAt: "$t(models.generic.updatedAt)" client: _name: "klient" _name_plural: "klienci" name: "$t(models.user.name)" - gender: "$t(dictionary.gender._name)" + createdAt: "$t(models.generic.createdAt)" + createdBy: "$t(models.generic.createdBy)" + updatedAt: "$t(models.generic.updatedAt)" + genderDictId: "$t(dictionary.gender._name)" meeting: _name: "spotkanie" diff --git a/resources/lang/pl_PL/tables.yml b/resources/lang/pl_PL/tables.yml index a4ac9c0dd..fed1ca9af 100644 --- a/resources/lang/pl_PL/tables.yml +++ b/resources/lang/pl_PL/tables.yml @@ -37,6 +37,14 @@ tables: columnNames: id: "$t(tables.tables.generic.columnNames.id)" name: "$t(models.staff.name)" + email: "$t(models.staff.email)" + hasEmailVerified: "$t(models.staff.hasEmailVerified)" + hasPassword: "$t(models.staff.hasPassword)" + passwordExpireAt: "$t(models.staff.passwordExpireAt)" + hasGlobalAdmin: "$t(models.staff.hasGlobalAdmin)" + createdAt: "$t(models.staff.createdAt)" + createdBy.name: "$t(models.staff.createdBy)" + updatedAt: "$t(models.staff.updatedAt)" clients: tableName: "$t(models.client._name_plural)" @@ -47,6 +55,10 @@ tables: columnNames: id: "$t(tables.tables.generic.columnNames.id)" name: "$t(models.client.name)" + createdAt: "$t(models.client.createdAt)" + createdBy.name: "$t(models.client.createdBy)" + updatedAt: "$t(models.client.updatedAt)" + genderDictId: "$t(models.client.genderDictId)" userFacilities: tableName: "$t(models.user.members)"