From 1e5f37b20aba31442e70dd4d52cf8dc585387918 Mon Sep 17 00:00:00 2001 From: Alexis Gousseau Date: Mon, 1 Dec 2025 14:42:50 +0100 Subject: [PATCH] feat: :sparkles: add google map in 'nous-connaitre' page --- .env.example | 3 + app/Enums/DynamicFieldTypes.php | 2 +- .../Back/CompanyActivityController.php | 239 +++++++++++++ .../Controllers/Back/CompanyController.php | 253 ++++++++++++++ .../Back/CompanySectorController.php | 239 +++++++++++++ app/Http/Middleware/HandleInertiaRequests.php | 40 ++- .../Back/Companies/StoreCompanyRequest.php | 80 +++++ .../Back/Companies/UpdateCompanyRequest.php | 18 + .../StoreCompanyActivityRequest.php | 50 +++ .../UpdateCompanyActivityRequest.php | 18 + .../StoreCompanySectorRequest.php | 48 +++ .../UpdateCompanySectorRequest.php | 18 + app/Models/Company.php | 149 ++++++++ app/Models/CompanyActivity.php | 155 +++++++++ app/Models/CompanySector.php | 153 +++++++++ app/Models/DynamicPage.php | 2 +- app/Models/News.php | 2 +- app/Policies/CompanyActivityPolicy.php | 109 ++++++ app/Policies/CompanyPolicy.php | 109 ++++++ app/Policies/CompanySectorPolicy.php | 109 ++++++ .../Front/Pages/KnowUs/OurImplantations.php | 42 +++ config/services.php | 3 + database/factories/CompanyFactory.php | 34 ++ .../2025_11_26_173420_create_companies.php | 134 ++++++++ database/seeders/CompanySeeder.php | 19 ++ database/seeders/DatabaseSeeder.php | 3 +- lang/en/back.php | 249 +++++++------- lang/en/front.php | 6 +- lang/en/models.php | 3 + lang/en/validation.php | 18 +- lang/fr/back.php | 251 +++++++------- lang/fr/front.php | 6 +- lang/fr/models.php | 3 + lang/fr/validation.php | 12 +- manifest.yaml | 1 + .../ts/back/Components/Layout/AppSidebar.tsx | 90 ++++- resources/ts/back/Pages/Companies/Create.tsx | 57 ++++ resources/ts/back/Pages/Companies/Edit.tsx | 58 ++++ resources/ts/back/Pages/Companies/Form.tsx | 317 ++++++++++++++++++ resources/ts/back/Pages/Companies/Index.tsx | 172 ++++++++++ resources/ts/back/Pages/Companies/Show.tsx | 128 +++++++ .../back/Pages/CompanyActivities/Create.tsx | 57 ++++ .../ts/back/Pages/CompanyActivities/Edit.tsx | 58 ++++ .../ts/back/Pages/CompanyActivities/Form.tsx | 160 +++++++++ .../ts/back/Pages/CompanyActivities/Index.tsx | 181 ++++++++++ .../ts/back/Pages/CompanyActivities/Show.tsx | 120 +++++++ .../ts/back/Pages/CompanySectors/Create.tsx | 57 ++++ .../ts/back/Pages/CompanySectors/Edit.tsx | 58 ++++ .../ts/back/Pages/CompanySectors/Form.tsx | 144 ++++++++ .../ts/back/Pages/CompanySectors/Index.tsx | 159 +++++++++ .../ts/back/Pages/CompanySectors/Show.tsx | 115 +++++++ resources/ts/back/Pages/DynamicPages/Form.tsx | 1 - resources/ts/back/types/global.d.ts | 42 ++- .../front/pages/join-us/join-us.blade.php | 3 +- .../pages/join-us/our-politics.blade.php | 2 +- .../pages/join-us/our-professions.blade.php | 3 +- .../front/pages/join-us/your-career.blade.php | 3 +- .../historic-slider.blade.php | 0 .../historical.blade.php | 4 +- .../our-governance.blade.php | 0 .../pages/know-us/our-implantations.blade.php | 280 ++++++++++++++++ .../our-organisation.blade.php | 0 .../pole-page-template.blade.php | 0 .../pages/our-jobs/our-professions.blade.php | 3 +- .../components/front/sections/title.blade.php | 2 +- resources/views/front/layouts/head.blade.php | 4 +- .../views/front/layouts/header.blade.php | 2 +- .../views/front/pages/espace-presse.blade.php | 3 +- .../views/front/pages/notre-pole.blade.php | 2 +- .../front/pages/nous-connaitre.blade.php | 20 +- routes/breadcrumbs-back.php | 99 ++++++ routes/web-back.php | 40 ++- 72 files changed, 4732 insertions(+), 292 deletions(-) create mode 100644 app/Http/Controllers/Back/CompanyActivityController.php create mode 100644 app/Http/Controllers/Back/CompanyController.php create mode 100644 app/Http/Controllers/Back/CompanySectorController.php create mode 100644 app/Http/Requests/Back/Companies/StoreCompanyRequest.php create mode 100644 app/Http/Requests/Back/Companies/UpdateCompanyRequest.php create mode 100644 app/Http/Requests/Back/CompanyActivities/StoreCompanyActivityRequest.php create mode 100644 app/Http/Requests/Back/CompanyActivities/UpdateCompanyActivityRequest.php create mode 100644 app/Http/Requests/Back/CompanySectors/StoreCompanySectorRequest.php create mode 100644 app/Http/Requests/Back/CompanySectors/UpdateCompanySectorRequest.php create mode 100644 app/Models/Company.php create mode 100644 app/Models/CompanyActivity.php create mode 100644 app/Models/CompanySector.php create mode 100644 app/Policies/CompanyActivityPolicy.php create mode 100644 app/Policies/CompanyPolicy.php create mode 100644 app/Policies/CompanySectorPolicy.php create mode 100644 app/View/Components/Front/Pages/KnowUs/OurImplantations.php create mode 100644 database/factories/CompanyFactory.php create mode 100644 database/migrations/2025_11_26_173420_create_companies.php create mode 100644 database/seeders/CompanySeeder.php create mode 100644 resources/ts/back/Pages/Companies/Create.tsx create mode 100644 resources/ts/back/Pages/Companies/Edit.tsx create mode 100644 resources/ts/back/Pages/Companies/Form.tsx create mode 100644 resources/ts/back/Pages/Companies/Index.tsx create mode 100644 resources/ts/back/Pages/Companies/Show.tsx create mode 100644 resources/ts/back/Pages/CompanyActivities/Create.tsx create mode 100644 resources/ts/back/Pages/CompanyActivities/Edit.tsx create mode 100644 resources/ts/back/Pages/CompanyActivities/Form.tsx create mode 100644 resources/ts/back/Pages/CompanyActivities/Index.tsx create mode 100644 resources/ts/back/Pages/CompanyActivities/Show.tsx create mode 100644 resources/ts/back/Pages/CompanySectors/Create.tsx create mode 100644 resources/ts/back/Pages/CompanySectors/Edit.tsx create mode 100644 resources/ts/back/Pages/CompanySectors/Form.tsx create mode 100644 resources/ts/back/Pages/CompanySectors/Index.tsx create mode 100644 resources/ts/back/Pages/CompanySectors/Show.tsx rename resources/views/components/front/pages/{known-us => know-us}/historic-slider.blade.php (100%) rename resources/views/components/front/pages/{known-us => know-us}/historical.blade.php (65%) rename resources/views/components/front/pages/{known-us => know-us}/our-governance.blade.php (100%) create mode 100644 resources/views/components/front/pages/know-us/our-implantations.blade.php rename resources/views/components/front/pages/{known-us => know-us}/our-organisation.blade.php (100%) rename resources/views/components/front/pages/{known-us => know-us}/pole-page-template.blade.php (100%) diff --git a/.env.example b/.env.example index eac8c7be..e0895926 100644 --- a/.env.example +++ b/.env.example @@ -67,3 +67,6 @@ SAML2_SP_CERT_x509= SAML2_SP_CERT_PRIVATEKEY= SAML2_CONTACT_TECHNICAL_EMAIL= SAML2_CONTACT_SUPPORT_EMAIL= + +# GOOGLE +GOOGLE_MAPS_KEY= \ No newline at end of file diff --git a/app/Enums/DynamicFieldTypes.php b/app/Enums/DynamicFieldTypes.php index c8f14afd..506458fc 100644 --- a/app/Enums/DynamicFieldTypes.php +++ b/app/Enums/DynamicFieldTypes.php @@ -63,7 +63,7 @@ enum DynamicFieldTypes: int self::vimeoId->name => 'required|string|min:8|max:10', self::youtubeId->name => 'required|string|size:11', self::date->name => 'required|date', - self::color->name => 'required|hex_color', + self::color->name => 'required|string|hex_color', ]; /** diff --git a/app/Http/Controllers/Back/CompanyActivityController.php b/app/Http/Controllers/Back/CompanyActivityController.php new file mode 100644 index 00000000..80d65081 --- /dev/null +++ b/app/Http/Controllers/Back/CompanyActivityController.php @@ -0,0 +1,239 @@ +authorizeResource(CompanyActivity::class); + } + + /** + * Display a listing of the resource. + * + * @param \Illuminate\Http\Request $request + * @return \Inertia\Response + */ + public function index(Request $request): \Inertia\Response + { + /** @var \Illuminate\Database\Eloquent\Builder<\App\Models\CompanyActivity> $query */ + $query = CompanyActivity::query(); + + if ($request->routeIs("back.company-activities.trash")) { + $query = $query->onlyTrashed(); + } + + /** @var string $search Search field */ + $search = $request->search; + if ($search) { + $this->searchQuery( + $query, + $search, + null, + 'name', + ); + } + $searchFields = \implode(', ', [ + trans('validation.attributes.name'), + ]); + + /** Sort columns with a query */ + $this->sortQuery($query); + + /** Custom pagination */ + $companyActivityModels = $this->paginate($query); + + return Inertia::render('CompanyActivities/Index', [ + 'companyActivityModels' => CommonResource::collection($companyActivityModels), + 'search' => $search, + 'searchFields' => $searchFields, + ]); + } + + /** + * Show the form for creating a new resource. + * + * @param \App\Models\CompanyActivity $company_activity + * @return \Inertia\Response + */ + public function create(CompanyActivity $company_activity): \Inertia\Response + { + return Inertia::render('CompanyActivities/Create', [ + 'data' => CommonResource::make($company_activity), + ]); + } + + /** + * Show a specific resource. + * + * @param \App\Models\CompanyActivity $company_activity + * @return \Inertia\Response + */ + public function show(CompanyActivity $company_activity): \Inertia\Response + { + return Inertia::render('CompanyActivities/Show', [ + 'data' => CommonResource::make($company_activity), + ]); + } + + /** + * Store a newly created resource. + * + * @param \App\Http\Requests\Back\CompanyActivities\StoreCompanyActivityRequest $request + * @return \Illuminate\Http\RedirectResponse + */ + public function store(StoreCompanyActivityRequest $request): \Illuminate\Http\RedirectResponse + { + return DB::transaction(function () use ($request) { + $pageConfigModel = new CompanyActivity(); + $pageConfigModel->fill($request->validated()); + + if ($pageConfigModel->saveOrFail()) { + return redirect()->route('back.company-activities.edit', $pageConfigModel) + ->with('success', __('crud.messages.has_been_created', [ + 'model' => Str::of(trans('models.classes.company'))->plural()->ucfirst() + ])); + } + return redirect()->back() + ->with('error', __('crud.messages.cannot_be_created', [ + 'model' => Str::of(trans('models.classes.company'))->plural()->ucfirst() + ])); + }); + } + + /** + * Show the form for editing the specified resource. + * + * @param \App\Models\CompanyActivity $company_activity + * @return \Inertia\Response + */ + public function edit(CompanyActivity $company_activity): \Inertia\Response + { + return Inertia::render('CompanyActivities/Edit', [ + 'data' => CommonResource::make($company_activity), + ]); + } + + /** + * Update the specified resource. + * + * @param \App\Http\Requests\Back\CompanyActivities\UpdateCompanyActivityRequest $request + * @param \App\Models\CompanyActivity $company_activity + * @return \Illuminate\Http\RedirectResponse + */ + public function update(UpdateCompanyActivityRequest $request, CompanyActivity $company_activity): \Illuminate\Http\RedirectResponse + { + return DB::transaction(function () use ($request, $company_activity) { + $company_activity->fill($request->validated()); + + if ($company_activity->saveOrFail()) { + return redirect()->route('back.company-activities.edit', $company_activity) + ->with('success', __('crud.messages.has_been_updated', [ + 'model' => Str::of(trans('models.classes.company'))->ucfirst() + ])); + } + return redirect()->route('back.company-activities.edit', $company_activity) + ->with('error', __('crud.messages.cannot_be_updated', [ + 'model' => Str::of(trans('models.classes.company'))->ucfirst() + ])); + }); + } + + /** + * Duplicate the specified resource. + * + * @param \App\Models\CompanyActivity $company_activity + * @return \Inertia\Response + */ + public function duplicate(CompanyActivity $company_activity): \Inertia\Response + { + return $this->create($company_activity->replicate()); + } + + /** + * Restore the specified resource. + * + * @param integer $company_activity + * @return \Illuminate\Http\RedirectResponse + */ + public function restore(int $company_activity): \Illuminate\Http\RedirectResponse + { + $company_activity = CompanyActivity::withTrashed()->findOrFail($company_activity); + /** @var array */ + $previousQueries = []; + \parse_str(\parse_url(url()->previous(), \PHP_URL_QUERY), $previousQueries); + if ($company_activity->restore()) { + return redirect()->route('back.company-activities.trash', $previousQueries) + ->with('success', __('crud.messages.has_been_restored', [ + 'model' => Str::of(trans('models.classes.company'))->plural()->ucfirst(), + ])); + } + return redirect()->back() + ->with('error', __('crud.messages.cannot_be_restored', [ + 'model' => Str::of(trans('models.classes.company'))->plural()->ucfirst(), + ])); + } + + /** + * Destroy the specified resource. + * + * @param \App\Models\CompanyActivity $company_activity + * @return \Illuminate\Http\RedirectResponse + */ + public function destroy(CompanyActivity $company_activity): \Illuminate\Http\RedirectResponse + { + /** @var array */ + $previousQueries = []; + \parse_str(\parse_url(url()->previous(), \PHP_URL_QUERY), $previousQueries); + if ($company_activity->delete()) { + return redirect()->route('back.company-activities.index', $previousQueries) + ->with('success', __('crud.messages.has_been_deleted', [ + 'model' => Str::of(trans('models.classes.company'))->plural()->ucfirst(), + ])); + } + return redirect()->back() + ->with('error', __('crud.messages.cannot_be_deleted', [ + 'model' => Str::of(trans('models.classes.company'))->plural()->ucfirst(), + ])); + } + + /** + * Destroy the specified resource. + * + * @param \App\Models\CompanyActivity|integer $company_activity + * @return \Illuminate\Http\RedirectResponse + */ + public function forceDestroy(CompanyActivity|int $company_activity): \Illuminate\Http\RedirectResponse + { + if (is_int($company_activity)) { + $company_activity = CompanyActivity::withTrashed()->findOrFail($company_activity); + } + /** @var array */ + $previousQueries = []; + \parse_str(\parse_url(url()->previous(), \PHP_URL_QUERY), $previousQueries); + if ($company_activity->forceDelete()) { + return redirect()->route('back.company-activities.trash', $previousQueries) + ->with('success', __('crud.messages.has_been_deleted', [ + 'model' => Str::of(trans('models.classes.company'))->plural()->ucfirst(), + ])); + } + return redirect()->back() + ->with('error', __('crud.messages.cannot_be_deleted', [ + 'model' => Str::of(trans('models.classes.company'))->plural()->ucfirst(), + ])); + } +} diff --git a/app/Http/Controllers/Back/CompanyController.php b/app/Http/Controllers/Back/CompanyController.php new file mode 100644 index 00000000..fb2b473e --- /dev/null +++ b/app/Http/Controllers/Back/CompanyController.php @@ -0,0 +1,253 @@ +authorizeResource(Company::class); + } + + /** + * Display a listing of the resource. + * + * @param \Illuminate\Http\Request $request + * @return \Inertia\Response + */ + public function index(Request $request): \Inertia\Response + { + /** @var \Illuminate\Database\Eloquent\Builder<\App\Models\Company> $query */ + $query = Company::query(); + + if ($request->routeIs("back.companies.trash")) { + $query = $query->onlyTrashed(); + } + + /** @var string $search Search field */ + $search = $request->search; + if ($search) { + $this->searchQuery( + $query, + $search, + null, + 'name', + 'latitude', + 'longitude', + ); + } + $searchFields = \implode(', ', [ + trans('validation.attributes.name'), + trans('validation.custom.latitude'), + trans('validation.custom.longitude'), + ]); + + /** Sort columns with a query */ + $this->sortQuery($query); + + /** Custom pagination */ + $companyModels = $this->paginate($query); + + return Inertia::render('Companies/Index', [ + 'companyModels' => CommonResource::collection($companyModels), + 'search' => $search, + 'searchFields' => $searchFields, + ]); + } + + /** + * Show the form for creating a new resource. + * + * @param \App\Models\Company $company + * @return \Inertia\Response + */ + public function create(Company $company): \Inertia\Response + { + $companyActivityModels = CompanyActivity::getAllCompanyActivities(); + $companySectorModels = CompanySector::getAllCompanySectors(); + return Inertia::render('Companies/Create', [ + 'data' => CommonResource::make($company), + 'companyActivityModels' => $companyActivityModels, + 'companySectorModels' => $companySectorModels, + ]); + } + + /** + * Show a specific resource. + * + * @param \App\Models\Company $company + * @return \Inertia\Response + */ + public function show(Company $company): \Inertia\Response + { + return Inertia::render('Companies/Show', [ + 'data' => CommonResource::make($company), + ]); + } + + /** + * Store a newly created resource. + * + * @param \App\Http\Requests\Back\Companies\StoreCompanyRequest $request + * @return \Illuminate\Http\RedirectResponse + */ + public function store(StoreCompanyRequest $request): \Illuminate\Http\RedirectResponse + { + return DB::transaction(function () use ($request) { + $pageConfigModel = new Company(); + $pageConfigModel->inertiaFill($request->validated()); + + if ($pageConfigModel->saveOrFail()) { + return redirect()->route('back.companies.edit', $pageConfigModel) + ->with('success', __('crud.messages.has_been_created', [ + 'model' => Str::of(trans('models.classes.company'))->plural()->ucfirst() + ])); + } + return redirect()->back() + ->with('error', __('crud.messages.cannot_be_created', [ + 'model' => Str::of(trans('models.classes.company'))->plural()->ucfirst() + ])); + }); + } + + /** + * Show the form for editing the specified resource. + * + * @param \App\Models\Company $company + * @return \Inertia\Response + */ + public function edit(Company $company): \Inertia\Response + { + $companyActivityModels = CompanyActivity::getAllCompanyActivities(); + $companySectorModels = CompanySector::getAllCompanySectors(); + return Inertia::render('Companies/Edit', [ + 'data' => CommonResource::make($company), + 'companyActivityModels' => $companyActivityModels, + 'companySectorModels' => $companySectorModels, + ]); + } + + /** + * Update the specified resource. + * + * @param \App\Http\Requests\Back\Companies\UpdateCompanyRequest $request + * @param \App\Models\Company $company + * @return \Illuminate\Http\RedirectResponse + */ + public function update(UpdateCompanyRequest $request, Company $company): \Illuminate\Http\RedirectResponse + { + return DB::transaction(function () use ($request, $company) { + $company->inertiaFill($request->validated()); + + if ($company->saveOrFail()) { + return redirect()->route('back.companies.edit', $company) + ->with('success', __('crud.messages.has_been_updated', [ + 'model' => Str::of(trans('models.classes.company'))->ucfirst() + ])); + } + return redirect()->route('back.companies.edit', $company) + ->with('error', __('crud.messages.cannot_be_updated', [ + 'model' => Str::of(trans('models.classes.company'))->ucfirst() + ])); + }); + } + + /** + * Duplicate the specified resource. + * + * @param \App\Models\Company $company + * @return \Inertia\Response + */ + public function duplicate(Company $company): \Inertia\Response + { + return $this->create($company->replicate()); + } + + /** + * Restore the specified resource. + * + * @param integer $company + * @return \Illuminate\Http\RedirectResponse + */ + public function restore(int $company): \Illuminate\Http\RedirectResponse + { + $company = Company::withTrashed()->findOrFail($company); + /** @var array */ + $previousQueries = []; + \parse_str(\parse_url(url()->previous(), \PHP_URL_QUERY), $previousQueries); + if ($company->restore()) { + return redirect()->route('back.companies.trash', $previousQueries) + ->with('success', __('crud.messages.has_been_restored', [ + 'model' => Str::of(trans('models.classes.company'))->plural()->ucfirst(), + ])); + } + return redirect()->back() + ->with('error', __('crud.messages.cannot_be_restored', [ + 'model' => Str::of(trans('models.classes.company'))->plural()->ucfirst(), + ])); + } + + /** + * Destroy the specified resource. + * + * @param \App\Models\Company $company + * @return \Illuminate\Http\RedirectResponse + */ + public function destroy(Company $company): \Illuminate\Http\RedirectResponse + { + /** @var array */ + $previousQueries = []; + \parse_str(\parse_url(url()->previous(), \PHP_URL_QUERY), $previousQueries); + if ($company->delete()) { + return redirect()->route('back.companies.index', $previousQueries) + ->with('success', __('crud.messages.has_been_deleted', [ + 'model' => Str::of(trans('models.classes.company'))->plural()->ucfirst(), + ])); + } + return redirect()->back() + ->with('error', __('crud.messages.cannot_be_deleted', [ + 'model' => Str::of(trans('models.classes.company'))->plural()->ucfirst(), + ])); + } + + /** + * Destroy the specified resource. + * + * @param \App\Models\Company|integer $company + * @return \Illuminate\Http\RedirectResponse + */ + public function forceDestroy(Company|int $company): \Illuminate\Http\RedirectResponse + { + if (is_int($company)) { + $company = Company::withTrashed()->findOrFail($company); + } + /** @var array */ + $previousQueries = []; + \parse_str(\parse_url(url()->previous(), \PHP_URL_QUERY), $previousQueries); + if ($company->forceDelete()) { + return redirect()->route('back.companies.trash', $previousQueries) + ->with('success', __('crud.messages.has_been_deleted', [ + 'model' => Str::of(trans('models.classes.company'))->plural()->ucfirst(), + ])); + } + return redirect()->back() + ->with('error', __('crud.messages.cannot_be_deleted', [ + 'model' => Str::of(trans('models.classes.company'))->plural()->ucfirst(), + ])); + } +} diff --git a/app/Http/Controllers/Back/CompanySectorController.php b/app/Http/Controllers/Back/CompanySectorController.php new file mode 100644 index 00000000..8d670a80 --- /dev/null +++ b/app/Http/Controllers/Back/CompanySectorController.php @@ -0,0 +1,239 @@ +authorizeResource(CompanySector::class); + } + + /** + * Display a listing of the resource. + * + * @param \Illuminate\Http\Request $request + * @return \Inertia\Response + */ + public function index(Request $request): \Inertia\Response + { + /** @var \Illuminate\Database\Eloquent\Builder<\App\Models\CompanySector> $query */ + $query = CompanySector::query(); + + if ($request->routeIs("back.company-sectors.trash")) { + $query = $query->onlyTrashed(); + } + + /** @var string $search Search field */ + $search = $request->search; + if ($search) { + $this->searchQuery( + $query, + $search, + null, + 'name', + ); + } + $searchFields = \implode(', ', [ + trans('validation.attributes.name'), + ]); + + /** Sort columns with a query */ + $this->sortQuery($query); + + /** Custom pagination */ + $companySectorModels = $this->paginate($query); + + return Inertia::render('CompanySectors/Index', [ + 'companySectorModels' => CommonResource::collection($companySectorModels), + 'search' => $search, + 'searchFields' => $searchFields, + ]); + } + + /** + * Show the form for creating a new resource. + * + * @param \App\Models\CompanySector $company_sector + * @return \Inertia\Response + */ + public function create(CompanySector $company_sector): \Inertia\Response + { + return Inertia::render('CompanySectors/Create', [ + 'data' => CommonResource::make($company_sector), + ]); + } + + /** + * Show a specific resource. + * + * @param \App\Models\CompanySector $company_sector + * @return \Inertia\Response + */ + public function show(CompanySector $company_sector): \Inertia\Response + { + return Inertia::render('CompanySectors/Show', [ + 'data' => CommonResource::make($company_sector), + ]); + } + + /** + * Store a newly created resource. + * + * @param \App\Http\Requests\Back\CompanySectors\StoreCompanySectorRequest $request + * @return \Illuminate\Http\RedirectResponse + */ + public function store(StoreCompanySectorRequest $request): \Illuminate\Http\RedirectResponse + { + return DB::transaction(function () use ($request) { + $pageConfigModel = new CompanySector(); + $pageConfigModel->fill($request->validated()); + + if ($pageConfigModel->saveOrFail()) { + return redirect()->route('back.company-sectors.edit', $pageConfigModel) + ->with('success', __('crud.messages.has_been_created', [ + 'model' => Str::of(trans('models.classes.company'))->plural()->ucfirst() + ])); + } + return redirect()->back() + ->with('error', __('crud.messages.cannot_be_created', [ + 'model' => Str::of(trans('models.classes.company'))->plural()->ucfirst() + ])); + }); + } + + /** + * Show the form for editing the specified resource. + * + * @param \App\Models\CompanySector $company_sector + * @return \Inertia\Response + */ + public function edit(CompanySector $company_sector): \Inertia\Response + { + return Inertia::render('CompanySectors/Edit', [ + 'data' => CommonResource::make($company_sector), + ]); + } + + /** + * Update the specified resource. + * + * @param \App\Http\Requests\Back\CompanySectors\UpdateCompanySectorRequest $request + * @param \App\Models\CompanySector $company_sector + * @return \Illuminate\Http\RedirectResponse + */ + public function update(UpdateCompanySectorRequest $request, CompanySector $company_sector): \Illuminate\Http\RedirectResponse + { + return DB::transaction(function () use ($request, $company_sector) { + $company_sector->fill($request->validated()); + + if ($company_sector->saveOrFail()) { + return redirect()->route('back.company-sectors.edit', $company_sector) + ->with('success', __('crud.messages.has_been_updated', [ + 'model' => Str::of(trans('models.classes.company'))->ucfirst() + ])); + } + return redirect()->route('back.company-sectors.edit', $company_sector) + ->with('error', __('crud.messages.cannot_be_updated', [ + 'model' => Str::of(trans('models.classes.company'))->ucfirst() + ])); + }); + } + + /** + * Duplicate the specified resource. + * + * @param \App\Models\CompanySector $company_sector + * @return \Inertia\Response + */ + public function duplicate(CompanySector $company_sector): \Inertia\Response + { + return $this->create($company_sector->replicate()); + } + + /** + * Restore the specified resource. + * + * @param integer $company_sector + * @return \Illuminate\Http\RedirectResponse + */ + public function restore(int $company_sector): \Illuminate\Http\RedirectResponse + { + $company_sector = CompanySector::withTrashed()->findOrFail($company_sector); + /** @var array */ + $previousQueries = []; + \parse_str(\parse_url(url()->previous(), \PHP_URL_QUERY), $previousQueries); + if ($company_sector->restore()) { + return redirect()->route('back.company-sectors.trash', $previousQueries) + ->with('success', __('crud.messages.has_been_restored', [ + 'model' => Str::of(trans('models.classes.company'))->plural()->ucfirst(), + ])); + } + return redirect()->back() + ->with('error', __('crud.messages.cannot_be_restored', [ + 'model' => Str::of(trans('models.classes.company'))->plural()->ucfirst(), + ])); + } + + /** + * Destroy the specified resource. + * + * @param \App\Models\CompanySector $company_sector + * @return \Illuminate\Http\RedirectResponse + */ + public function destroy(CompanySector $company_sector): \Illuminate\Http\RedirectResponse + { + /** @var array */ + $previousQueries = []; + \parse_str(\parse_url(url()->previous(), \PHP_URL_QUERY), $previousQueries); + if ($company_sector->delete()) { + return redirect()->route('back.company-sectors.index', $previousQueries) + ->with('success', __('crud.messages.has_been_deleted', [ + 'model' => Str::of(trans('models.classes.company'))->plural()->ucfirst(), + ])); + } + return redirect()->back() + ->with('error', __('crud.messages.cannot_be_deleted', [ + 'model' => Str::of(trans('models.classes.company'))->plural()->ucfirst(), + ])); + } + + /** + * Destroy the specified resource. + * + * @param \App\Models\CompanySector|integer $company_sector + * @return \Illuminate\Http\RedirectResponse + */ + public function forceDestroy(CompanySector|int $company_sector): \Illuminate\Http\RedirectResponse + { + if (is_int($company_sector)) { + $company_sector = CompanySector::withTrashed()->findOrFail($company_sector); + } + /** @var array */ + $previousQueries = []; + \parse_str(\parse_url(url()->previous(), \PHP_URL_QUERY), $previousQueries); + if ($company_sector->forceDelete()) { + return redirect()->route('back.company-sectors.trash', $previousQueries) + ->with('success', __('crud.messages.has_been_deleted', [ + 'model' => Str::of(trans('models.classes.company'))->plural()->ucfirst(), + ])); + } + return redirect()->back() + ->with('error', __('crud.messages.cannot_be_deleted', [ + 'model' => Str::of(trans('models.classes.company'))->plural()->ucfirst(), + ])); + } +} diff --git a/app/Http/Middleware/HandleInertiaRequests.php b/app/Http/Middleware/HandleInertiaRequests.php index 2585da01..1b3984ad 100644 --- a/app/Http/Middleware/HandleInertiaRequests.php +++ b/app/Http/Middleware/HandleInertiaRequests.php @@ -7,10 +7,13 @@ use App\Enums\DynamicPages\PageStatusEnum; use App\Enums\News\NewsCategoryEnum; use App\Enums\News\NewsStatusEnum; use App\Helpers\TranslationHelper; -use App\Models\DynamicPage; -use App\Models\PageConfig; +use App\Models\Company; +use App\Models\CompanyActivity; +use App\Models\CompanySector; use App\Models\ContactCount; +use App\Models\DynamicPage; use App\Models\News; +use App\Models\PageConfig; use Diglactic\Breadcrumbs\Breadcrumbs; use Illuminate\Http\Request; use Illuminate\Support\Facades\Gate; @@ -49,7 +52,7 @@ class HandleInertiaRequests extends Middleware $props = [ ...parent::share($request), - 'appEnv' => [ + 'appEnv' => [ 'mode' => config('app.env'), 'name' => config('app.name'), 'url' => config('app.url'), @@ -57,34 +60,49 @@ class HandleInertiaRequests extends Middleware 'locales' => config('app.locales'), 'fallbackLocale' => app()->getFallbackLocale(), ], - 'auth' => [ + 'auth' => [ 'user' => $request->user(), 'policies' => [ - 'activityLogs' => [ + 'activityLogs' => [ 'viewAny' => Gate::allows('viewAny', User::class), ], - 'users' => [ + 'users' => [ 'viewAny' => Gate::allows('viewAny', User::class), 'create' => Gate::allows('create', User::class), ], - 'dynamicPages' => [ + 'dynamicPages' => [ 'viewAny' => Gate::allows('viewAny', DynamicPage::class), 'viewTrash' => Gate::allows('viewTrash', DynamicPage::class), 'create' => Gate::allows('create', DynamicPage::class), ], - 'pageConfigs' => [ + 'pageConfigs' => [ 'viewAny' => Gate::allows('viewAny', PageConfig::class), 'viewTrash' => Gate::allows('viewTrash', PageConfig::class), 'create' => Gate::allows('create', PageConfig::class), ], - 'contact_counts' => [ + 'contact_counts' => [ "viewAny" => Gate::allows('viewAny', ContactCount::class) ], - 'news' => [ + 'news' => [ 'viewAny' => Gate::allows('viewAny', News::class), 'viewTrash' => Gate::allows('viewTrash', News::class), 'create' => Gate::allows('create', News::class), - ] + ], + 'companies' => [ + 'viewAny' => Gate::allows('viewAny', Company::class), + 'viewTrash' => Gate::allows('viewTrash', Company::class), + 'create' => Gate::allows('create', Company::class), + ], + 'companyActivities' => [ + 'viewAny' => Gate::allows('viewAny', CompanyActivity::class), + 'viewTrash' => Gate::allows('viewTrash', CompanyActivity::class), + 'create' => Gate::allows('create', CompanyActivity::class), + ], + 'companySectors' => [ + 'viewAny' => Gate::allows('viewAny', CompanySector::class), + 'viewTrash' => Gate::allows('viewTrash', CompanySector::class), + 'create' => Gate::allows('create', CompanySector::class), + ], ] ], 'enumItemsPerPagination' => ItemsPerPaginationEnum::toArray(), diff --git a/app/Http/Requests/Back/Companies/StoreCompanyRequest.php b/app/Http/Requests/Back/Companies/StoreCompanyRequest.php new file mode 100644 index 00000000..2ef29680 --- /dev/null +++ b/app/Http/Requests/Back/Companies/StoreCompanyRequest.php @@ -0,0 +1,80 @@ +merge([ + 'published' => $this->boolean('published'), + ]); + $this->mergeInertiaPicture(); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules(): array + { + return [ + 'name' => 'required|string|between:3,255', + 'logo' => $this->pictureRules('required|nullable|file|mimes:jpg,jpeg,png,webp|max:5120|dimensions:width=500,height=500'), + 'responsable' => 'required|nullable|string|between:3,255', + 'url' => 'required|nullable|string|between:3,255', + 'informations' => 'required|string|between:3,255', + 'employees' => 'required|nullable|numeric|between:0,100000', + 'latitude' => 'required|numeric|between:-90,90', + 'longitude' => 'required|numeric|between:-180,180', + 'activity_id' => 'required|numeric|exists:company_activities,id', + 'sector_id' => 'required|nullable|numeric|exists:company_sectors,id', + 'published' => 'required|boolean', + ]; + } + + /** + * Get custom attributes for validator errors. + * + * @return array + */ + public function attributes(): array + { + return [ + 'name' => trans('validation.attributes.name'), + 'logo' => trans('validation.custom.logo'), + 'informations' => trans('validation.custom.informations'), + 'responsable' => trans('validation.custom.responsable'), + 'latitude' => trans('validation.custom.latitude'), + 'longitude' => trans('validation.custom.longitude'), + 'activity_id' => trans('models.classes.activity'), + 'sector_id' => trans('models.classes.sector'), + 'published' => trans('validation.custom.published'), + ]; + } +} diff --git a/app/Http/Requests/Back/Companies/UpdateCompanyRequest.php b/app/Http/Requests/Back/Companies/UpdateCompanyRequest.php new file mode 100644 index 00000000..3798a43d --- /dev/null +++ b/app/Http/Requests/Back/Companies/UpdateCompanyRequest.php @@ -0,0 +1,18 @@ +route('company')); + } +} diff --git a/app/Http/Requests/Back/CompanyActivities/StoreCompanyActivityRequest.php b/app/Http/Requests/Back/CompanyActivities/StoreCompanyActivityRequest.php new file mode 100644 index 00000000..18107243 --- /dev/null +++ b/app/Http/Requests/Back/CompanyActivities/StoreCompanyActivityRequest.php @@ -0,0 +1,50 @@ + 'required|string|between:3,255', + 'color' => 'required|string|hex_color', + 'published' => 'required|boolean', + ]; + } + + /** + * Get custom attributes for validator errors. + * + * @return array + */ + public function attributes(): array + { + return [ + 'name' => trans('validation.custom.name'), + 'color' => trans('validation.custom.color'), + 'published' => trans('validation.custom.published'), + ]; + } +} diff --git a/app/Http/Requests/Back/CompanyActivities/UpdateCompanyActivityRequest.php b/app/Http/Requests/Back/CompanyActivities/UpdateCompanyActivityRequest.php new file mode 100644 index 00000000..7ecc3d66 --- /dev/null +++ b/app/Http/Requests/Back/CompanyActivities/UpdateCompanyActivityRequest.php @@ -0,0 +1,18 @@ +route('company_activity')); + } +} diff --git a/app/Http/Requests/Back/CompanySectors/StoreCompanySectorRequest.php b/app/Http/Requests/Back/CompanySectors/StoreCompanySectorRequest.php new file mode 100644 index 00000000..6fbe4cb6 --- /dev/null +++ b/app/Http/Requests/Back/CompanySectors/StoreCompanySectorRequest.php @@ -0,0 +1,48 @@ + 'required|string|between:3,255', + 'published' => 'required|boolean', + ]; + } + + /** + * Get custom attributes for validator errors. + * + * @return array + */ + public function attributes(): array + { + return [ + 'name' => trans('validation.custom.name'), + 'published' => trans('validation.custom.published'), + ]; + } +} diff --git a/app/Http/Requests/Back/CompanySectors/UpdateCompanySectorRequest.php b/app/Http/Requests/Back/CompanySectors/UpdateCompanySectorRequest.php new file mode 100644 index 00000000..6c577b36 --- /dev/null +++ b/app/Http/Requests/Back/CompanySectors/UpdateCompanySectorRequest.php @@ -0,0 +1,18 @@ +route('company_sector')); + } +} diff --git a/app/Models/Company.php b/app/Models/Company.php new file mode 100644 index 00000000..3fcc7946 --- /dev/null +++ b/app/Models/Company.php @@ -0,0 +1,149 @@ + + */ + protected $fillable = [ + 'name', + 'logo', + 'responsable', + 'url', + 'informations', + 'employees', + 'latitude', + 'longitude', + 'activity_id', + 'sector_id', + 'published', + ]; + + /** + * The attributes that should be cast. + * + * @var array + */ + protected $casts = [ + 'published' => 'boolean', + ]; + + /** + * Perform any actions required after the model boots. + * + * @return void + */ + protected static function booted(): void + { + static::created(function () { + self::resetCache(); + }); + static::updated(function () { + self::resetCache(); + }); + static::deleted(function () { + self::resetCache(); + }); + static::restored(function () { + self::resetCache(); + }); + static::forceDeleted(function () { + self::resetCache(); + }); + } + + /** + * Reset all cache elements related to this model. + * + * @return void + */ + public static function resetCache(): void + { + Cache::forget('allCompanies'); + self::getAllCompanies(); + + Cache::forget('publishedCompanies'); + self::getPublishedCompanies(); + } + + /** + * Get all companies. + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public static function getAllCompanies(): \Illuminate\Database\Eloquent\Collection + { + return Cache::remember('allCompanies', 86400, function () { + return self::query()->with(['companyActivity', 'companySector'])->get(); + }); + } + + /** + * Get all published companies. + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public static function getPublishedCompanies(): \Illuminate\Database\Eloquent\Collection + { + return Cache::remember('publishedCompanies', 86400, function () { + return self::getAllCompanies()->where('published', true); + }); + } + + // * RELATIONSHIPS + + /** + * Get the activity for this company. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo<\App\Models\CompanyActivity,$this> + */ + public function companyActivity(): \Illuminate\Database\Eloquent\Relations\BelongsTo + { + return $this->belongsTo(CompanyActivity::class, 'activity_id'); + } + + /** + * Get the sector for this company. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo<\App\Models\CompanySector,$this> + */ + public function companySector(): \Illuminate\Database\Eloquent\Relations\BelongsTo + { + return $this->belongsTo(CompanySector::class, 'sector_id'); + } +} \ No newline at end of file diff --git a/app/Models/CompanyActivity.php b/app/Models/CompanyActivity.php new file mode 100644 index 00000000..7508f4bc --- /dev/null +++ b/app/Models/CompanyActivity.php @@ -0,0 +1,155 @@ + + */ + protected $fillable = [ + 'name', + 'color', + 'published', + ]; + + /** + * The translatable columns. + * + * @var list + */ + public $translatable = [ + 'name', + ]; + + /** + * The attributes that should be cast. + * + * @var array + */ + protected $casts = [ + 'published' => 'boolean', + ]; + + /** + * Perform any actions required after the model boots. + * + * @return void + */ + protected static function booted(): void + { + static::creating(function (self $model) { + self::manageFields($model); + }); + static::created(function (self $model) { + self::resetCache(); + }); + static::updating(function (self $model) { + self::manageFields($model); + }); + static::updated(function () { + self::resetCache(); + }); + static::deleted(function () { + self::resetCache(); + }); + static::restored(function () { + self::resetCache(); + }); + static::forceDeleted(function () { + self::resetCache(); + }); + } + + // * METHODS + + /** + * Manage model fields. + * + * @param self $model + * @return void + */ + private static function manageFields(self $model): void + { + TranslationHelper::assertTranslationFieldIsUnique($model, $model->name, 'name'); + self::validateFallbackTranslations($model); + } + + /** + * Assert fallback locale translation is present. + * + * @param self $model + * @return void + * @throws \Illuminate\Validation\ValidationException Translations missing. + */ + public static function validateFallbackTranslations(self $model): void + { + if (!$model->published) { + return; + } + TranslationHelper::validateFallbackTranslations($model); + } + + /** + * Reset all cache elements related to this model. + * + * @return void + */ + public static function resetCache(): void + { + Cache::forget('allCompanyActivities'); + self::getAllCompanyActivities(); + + Cache::forget('publishedCompanyActivities'); + self::getPublishedCompanyActivities(); + } + + /** + * Get all company activities. + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public static function getAllCompanyActivities(): \Illuminate\Database\Eloquent\Collection + { + return Cache::remember('allCompanyActivities', 86400, function () { + return self::query()->get(); + }); + } + + /** + * Get all published company activities. + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public static function getPublishedCompanyActivities(): \Illuminate\Database\Eloquent\Collection + { + return Cache::remember('publishedCompanyActivities', 86400, function () { + return self::getAllCompanyActivities()->where('published', true); + }); + } +} \ No newline at end of file diff --git a/app/Models/CompanySector.php b/app/Models/CompanySector.php new file mode 100644 index 00000000..1132b199 --- /dev/null +++ b/app/Models/CompanySector.php @@ -0,0 +1,153 @@ + + */ + protected $fillable = [ + 'name', + 'published', + ]; + + /** + * The translatable columns. + * + * @var list + */ + public $translatable = [ + 'name', + ]; + + /** + * The attributes that should be cast. + * + * @var array + */ + protected $casts = [ + 'published' => 'boolean', + ]; + + /** + * Perform any actions required after the model boots. + * + * @return void + */ + protected static function booted(): void + { + static::creating(function (self $model) { + self::manageFields($model); + }); + static::created(function (self $model) { + self::resetCache(); + }); + static::updating(function (self $model) { + self::manageFields($model); + }); + static::updated(function () { + self::resetCache(); + }); + static::deleted(function () { + self::resetCache(); + }); + static::restored(function () { + self::resetCache(); + }); + static::forceDeleted(function () { + self::resetCache(); + }); + } + + // * METHODS + + /** + * Manage model fields. + * + * @param self $model + * @return void + */ + private static function manageFields(self $model): void + { + TranslationHelper::assertTranslationFieldIsUnique($model, $model->name, 'name'); + self::validateFallbackTranslations($model); + } + + /** + * Assert fallback locale translation is present. + * + * @param self $model + * @return void + * @throws \Illuminate\Validation\ValidationException Translations missing. + */ + public static function validateFallbackTranslations(self $model): void + { + if (!$model->published) { + return; + } + TranslationHelper::validateFallbackTranslations($model); + } + + /** + * Reset all cache elements related to this model. + * + * @return void + */ + public static function resetCache(): void + { + Cache::forget('allCompanySectors'); + self::getAllCompanySectors(); + + Cache::forget('publishedCompanySectors'); + self::getPublishedCompanySectors(); + } + + /** + * Get all company sectors. + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public static function getAllCompanySectors(): \Illuminate\Database\Eloquent\Collection + { + return Cache::remember('allCompanySectors', 86400, function () { + return self::query()->get(); + }); + } + + /** + * Get all published company sectors. + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public static function getPublishedCompanySectors(): \Illuminate\Database\Eloquent\Collection + { + return Cache::remember('publishedCompanySectors', 86400, function () { + return self::getAllCompanySectors()->where('published', true); + }); + } +} \ No newline at end of file diff --git a/app/Models/DynamicPage.php b/app/Models/DynamicPage.php index 75db20e0..13f1c7aa 100644 --- a/app/Models/DynamicPage.php +++ b/app/Models/DynamicPage.php @@ -235,7 +235,7 @@ class DynamicPage extends Model implements TranslatableModel */ public static function validateFallbackTranslations(self $model): void { - if (! $model->status->equals(PageStatusEnum::published)) { + if (!$model->status->equals(PageStatusEnum::published)) { return; } TranslationHelper::validateFallbackTranslations($model); diff --git a/app/Models/News.php b/app/Models/News.php index 2e5f8781..4b186f9a 100644 --- a/app/Models/News.php +++ b/app/Models/News.php @@ -320,7 +320,7 @@ class News extends Model implements TranslatableModel */ public static function validateFallbackTranslations(self $model): void { - if (! $model->status->equals(NewsStatusEnum::published)) { + if (!$model->status->equals(NewsStatusEnum::published)) { return; } TranslationHelper::validateFallbackTranslations($model); diff --git a/app/Policies/CompanyActivityPolicy.php b/app/Policies/CompanyActivityPolicy.php new file mode 100644 index 00000000..ec609f4f --- /dev/null +++ b/app/Policies/CompanyActivityPolicy.php @@ -0,0 +1,109 @@ +id = $id; + $this->implantations = $implantations; + + $this->companyModels = Company::getPublishedCompanies()->whereNotNull('sector_id')->values(); + + $this->companyActivityModels = CompanyActivity::getPublishedCompanyActivities()->values(); + } + + /** + * Get the view / contents that represent the component. + * + * @return \Illuminate\Contracts\View\View|\Closure|string + */ + public function render(): \Illuminate\Contracts\View\View|\Closure|string + { + return view('components.front.pages.know-us.our-implantations', [ + 'companyModels' => $this->companyModels, + 'companyActivityModels' => $this->companyActivityModels, + ]); + } +} diff --git a/config/services.php b/config/services.php index 7eac995b..994d6fab 100644 --- a/config/services.php +++ b/config/services.php @@ -35,4 +35,7 @@ return [ ], ], + 'google' => [ + 'maps' => env('GOOGLE_MAPS_KEY'), + ], ]; diff --git a/database/factories/CompanyFactory.php b/database/factories/CompanyFactory.php new file mode 100644 index 00000000..5fda6d51 --- /dev/null +++ b/database/factories/CompanyFactory.php @@ -0,0 +1,34 @@ + + */ + public function definition(): array + { + $companyActivityModel = fake()->randomElement(CompanyActivity::all()); + $companySectorModel = fake()->randomElement(CompanySector::all()); + + return [ + 'name' => fake()->company(), + 'responsable' => fake()->name(), + 'informations' => fake()->text(200), + 'latitude' => fake()->latitude(), + 'longitude' => fake()->longitude(), + 'activity_id' => $companyActivityModel->getKey(), + 'sector_id' => $companySectorModel->getKey(), + 'published' => fake()->boolean(50), + ]; + } +} diff --git a/database/migrations/2025_11_26_173420_create_companies.php b/database/migrations/2025_11_26_173420_create_companies.php new file mode 100644 index 00000000..13ca6c7d --- /dev/null +++ b/database/migrations/2025_11_26_173420_create_companies.php @@ -0,0 +1,134 @@ +id(); + $table->string('name')->unique()->comment('Name of the company activity.'); + $table->string('color')->comment('Color of the company activity.'); + $table->boolean('published')->comment('Publish status of the company activity.'); + $table->timestamps(); + $table->softDeletes(); + }); + + Schema::create('company_sectors', function (Blueprint $table) { + $table->id(); + $table->string('name')->unique()->comment('Name of the company sector.'); + $table->boolean('published')->comment('Publish status of the company sector.'); + $table->timestamps(); + $table->softDeletes(); + }); + + Schema::create('companies', function (Blueprint $table) { + $table->id(); + $table->string('name')->unique()->comment('Name of the company.'); + $table->string('logo')->nullable()->comment('Logo of the company.'); + $table->string('responsable')->nullable()->comment('Responsable of the company.'); + $table->string('url')->nullable()->comment('Link the website of the company.'); + $table->text('informations')->comment('Informations of the company.'); + $table->mediumInteger('employees')->nullable()->comment('Effectif number of of the company.'); + $table->float('latitude')->comment('Latitude coordination of the company.'); + $table->float('longitude')->comment('Longitude of the company.'); + $table->foreignId('activity_id')->comment('Activity of the company.') + ->constrained('company_activities')->onUpdate('restrict')->onDelete('restrict'); + $table->foreignId('sector_id')->nullable()->comment('Sector of the company.') + ->constrained('company_sectors')->onUpdate('restrict')->onDelete('restrict'); + $table->boolean('published')->comment('Publish status of the company.'); + $table->timestamps(); + $table->softDeletes(); + }); + + // Export from wordpress... + $jsonPath = storage_path("uploads/export/societes.json"); + if (file_exists($jsonPath)) { + $jsonContent = file_get_contents($jsonPath); + $data = json_decode($jsonContent, true); + + // Seed sectors. + $sectors = array_unique(array_map(fn($array) => $array['filiere'] ?? null, $data)); + $sectors = array_filter($sectors); + $sectors = array_values($sectors); + sort($sectors); + foreach ($sectors as $key => $sector) { + $sectorModel = new CompanySector(); + $sectorModel->name = $sector; + $sectorModel->published = true; + $sectorModel->save(); + } + + // Seed activities. + $activities = array_unique(array_map(fn($array) => $array['type_activite'], $data)); + $activities = array_values($activities); + sort($activities); + foreach ($activities as $key => $activity) { + $activityModel = new CompanyActivity(); + $activityModel->name = Str::ucFirst($activity); + $activityModel->color = "#b43534"; + $activityModel->published = true; + $activityModel->save(); + } + + // Seed companies. + foreach ($data as $value) { + if ($value['logo']) { + $logoPath = explode("https://www.ldc.fr/app/", $value['logo']); + $logoPath = explode("https://www.ldc.fr/content/", $logoPath[count($logoPath) - 1]); + $logoPath = \storage_path($logoPath[count($logoPath) - 1]); + if (!file_exists($logoPath)) { + $logoPath = null; + } + } else { + $logoPath = null; + } + + $companyModel = new Company(); + $companyModel->name = $value['titre']; + $companyModel->logo = !is_null($logoPath) ? FileHelper::storeFile($companyModel, new \SplFileInfo($logoPath)) : $logoPath; + $companyModel->responsable = isset($value['responsable']) && !empty($value['responsable']) ? $value['responsable'] : null; + $companyModel->url = isset($value['url']) && !empty($value['url']) ? $value['url'] : null; + $companyModel->informations = $value['adresse']; + $companyModel->latitude = $value['latitude']; + $companyModel->longitude = $value['longitude']; + $companyModel->employees = isset($value['effectif']) && !empty($value['effectif']) ? (int) $value['effectif'] : null; + $companyModel->activity_id = CompanyActivity::getAllCompanyActivities() + ->where('name', Str::ucFirst($value['type_activite'])) + ->first() + ->getKey(); + $companyModel->sector_id = isset($value['filiere']) ? CompanySector::getAllCompanySectors() + ->where('name', Str::ucFirst($value['filiere'])) + ->first() + ->getKey() : null; + $companyModel->published = true; + $companyModel->saveQuietly(); + } + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down(): void + { + Schema::dropIfExists('companies'); + Schema::dropIfExists('company_activities'); + Schema::dropIfExists('company_sectors'); + } +}; diff --git a/database/seeders/CompanySeeder.php b/database/seeders/CompanySeeder.php new file mode 100644 index 00000000..71a50c0b --- /dev/null +++ b/database/seeders/CompanySeeder.php @@ -0,0 +1,19 @@ +create(); + } +} diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 1461d12d..8746d6e5 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -16,7 +16,8 @@ class DatabaseSeeder extends Seeder $this->call([ PageConfigSeeder::class, DynamicPageSeeder::class, - NewsSeeder::class + NewsSeeder::class, + CompanySeeder::class, ]); } } diff --git a/lang/en/back.php b/lang/en/back.php index f323ba7a..0a20f1fd 100644 --- a/lang/en/back.php +++ b/lang/en/back.php @@ -1,143 +1,147 @@ "link to your page", + "access_to_front_page" => "link to your page", "access_to_front_page_when_published" => "link to your page when published", - "login_title" => "Authentication", - "login_desc" => "Log in to access the administrative part of your website + "login_title" => "Authentication", + "login_desc" => "Log in to access the administrative part of your website :appName !", - "login_btn" => "Connection to UWIL Support", - "login_unpublished_user" => "Your account has been deactivated, please contact a site administrator.", - "dashboard" => "Dashboard", - "your_website" => "Your website", - "pages" => "Pages", - "modules" => "Modules", - "telescope" => "Telescope", - "yes_delete" => "Yes, delete", - "yes_update" => "Yes, update", - "yes_restore" => "Yes, restore", - "yes_archive" => "Yes, archive", - "no_cancel" => "No, cancel", - "yes" => "Yes", - "no" => "No", - "are_you_sure" => "Are you sure ?", - "trash_data" => "All data will be archived !", - "restore_data" => "All data will be restored !", - "lost_data" => "All data will be lost forever !", - "model_action_updated_at" => "Last modified on :", - "profile" => "Profile", - "disconnect" => "Disconnect", - "sidebar_trigger_tooltip" => "Collapse/expand navigation bar", - "warning" => "Warning", - "warning_production" => "You are currently logged into PRODUCTION. + "login_btn" => "Connection to UWIL Support", + "login_unpublished_user" => "Your account has been deactivated, please contact a site administrator.", + "dashboard" => "Dashboard", + "your_website" => "Your website", + "pages" => "Pages", + "modules" => "Modules", + "telescope" => "Telescope", + "yes_delete" => "Yes, delete", + "yes_update" => "Yes, update", + "yes_restore" => "Yes, restore", + "yes_archive" => "Yes, archive", + "no_cancel" => "No, cancel", + "yes" => "Yes", + "no" => "No", + "are_you_sure" => "Are you sure ?", + "trash_data" => "All data will be archived !", + "restore_data" => "All data will be restored !", + "lost_data" => "All data will be lost forever !", + "model_action_updated_at" => "Last modified on :", + "profile" => "Profile", + "disconnect" => "Disconnect", + "sidebar_trigger_tooltip" => "Collapse/expand navigation bar", + "warning" => "Warning", + "warning_production" => "You are currently logged into PRODUCTION. To test, please connect to the recipe !", - "warning_trash" => "Deletion of entries after 30 days spent as an archive !", - "dashboard_paragraph_1" => "Welcome to your website's back-office + "warning_trash" => "Deletion of entries after 30 days spent as an archive !", + "dashboard_paragraph_1" => "Welcome to your website's back-office :appName.", - "dashboard_paragraph_2" => "Here you can manage content that appears on your website, such as images, + "dashboard_paragraph_2" => "Here you can manage content that appears on your website, such as images, text and much more.", - "dashboard_paragraph_3" => "UWIL supports you in the + "dashboard_paragraph_3" => "UWIL supports you in the conception and the design of your current and future projects.", - "dashboard_paragraph_4" => "Don't hesitate to use our tools UWIL by LDC :", - "uwil_report_desc" => "Access your site statistics via our tool", - "uwil_support_desc" => "If you have any problems or would like to make any changes, please contact us via + "dashboard_paragraph_4" => "Don't hesitate to use our tools UWIL by LDC :", + "uwil_report_desc" => "Access your site statistics via our tool", + "uwil_support_desc" => "If you have any problems or would like to make any changes, please contact us via our tool", - "uwil_expo_desc" => "...", - "uwil_util_tooltip" => "Access our tool in a new tab", - "words" => "Words : ", - "characters" => "Characters : ", - "table_no_results" => "No results.", - "table_field" => "Field", - "table_value" => "Value", - "table_not_known" => "Not known", - "enter_text_here" => "Insert text here", - "enter_number_here" => "Insert number here", - "errors" => "Errors", - "light" => "Light", - "dark" => "Dark", - "system" => "System", - "mods" => "Mods", - "languages" => "Languages", - "settings" => "Settings", - "crud_back_to_list" => "Back to the list of entries", - "crud_add_entry" => "Add a new entry", - "crud_access_trash" => "Access archived entries", - "table_search" => "Search by :searchFields", - "table_search_reset" => "Reset the search", - "table_filter_button" => "Filter results by :field", - "table_filter_reset" => "Remove all selected filters", - "form_title_additional_files" => "Additionnal files", - "form_subtitle_additional_files" => "Add additionnal files", - "form_title_global" => "General information", - "form_subtitle_global" => "Modify the main information related to this data model.", - "form_title_visibility" => "Visibility", - "form_subtitle_visibility" => "Manage account display.", - "form_title_isLocked" => "Restriction", - "form_subtitle_isLocked" => "Manage page locking.", - "form_associate_to" => ":attribute associated to this model|:attribute associated to this model", - "form_associate_to_plural" => ":attribute associated to this model|:attribute associated to this model", - "form_title_config" => "Setup", - "form_subtitle_config" => "Manage configuration settings.", - "form_title_page" => "Configuration", - "form_subtitle_page" => "Manage the content for a dynamic page.", - "form_title_files" => "Files", - "form_subtitle_files" => "Manage files of the model.", - "form_title_seo" => "SEO fields", - "form_subtitle_seo" => "Manage SEO fields of the model", - "form_title_content" => "Content", - "form_subtitle_content" => "Manage content of the model", - "form_title_configuration" => "Configuration", - "form_subtitle_configuration" => "Manage model configuration.", - "form_title_display" => "Display", - "form_subtitle_display" => "Manage the final display of the model", - "access_model" => "Access to the :model", - "close" => "Close", - "clear" => "clear", - "config_modal_title" => "Preview", - "config_modal_descripion" => "Contents of the selected configuration", - "config_none_selected" => "No configuration selected", - "config_select_fields" => "Overwrite fields with those of an existing language", - "config_save_warning" => "The configuration of related pages in :locale must be updated accordingly.", - "config_save_warning_list" => "Here is the list of :models concerned:|Here is the list of :models concerned:", - "config_archived" => "This configuration is currently archived", - "config_complete_label" => "Copy the complete label of the input", - "entries_count" => ":length entry filled in|:length entries filled in", - "new_field" => "Add a new field", - "delete_field" => "Delete this field", - "dnd_field" => "Move this field", - "list_children_needed" => "Children are required for this type :enumLabel", - "empty_warning" => "No data recorded", - "page_locked" => "This page is currently locked", - "unsupported_type" => "Unsupported type:", - "missing_translations" => "The translation of the :field for the language :locales is missing.|The translation + "uwil_expo_desc" => "...", + "uwil_util_tooltip" => "Access our tool in a new tab", + "words" => "Words : ", + "characters" => "Characters : ", + "table_no_results" => "No results.", + "table_field" => "Field", + "table_value" => "Value", + "table_not_known" => "Not known", + "enter_text_here" => "Insert text here", + "enter_number_here" => "Insert number here", + "errors" => "Errors", + "light" => "Light", + "dark" => "Dark", + "system" => "System", + "mods" => "Mods", + "languages" => "Languages", + "settings" => "Settings", + "crud_back_to_list" => "Back to the list of entries", + "crud_add_entry" => "Add a new entry", + "crud_access_trash" => "Access archived entries", + "table_search" => "Search by :searchFields", + "table_search_reset" => "Reset the search", + "table_filter_button" => "Filter results by :field", + "table_filter_reset" => "Remove all selected filters", + "form_title_additional_files" => "Additionnal files", + "form_subtitle_additional_files" => "Add additionnal files", + "form_title_global" => "General information", + "form_subtitle_global" => "Modify the main information related to this data model.", + "form_title_visibility" => "Visibility", + "form_subtitle_visibility" => "Manage account display.", + "form_title_isLocked" => "Restriction", + "form_subtitle_isLocked" => "Manage page locking.", + "form_associate_to" => ":attribute associated to this model|:attribute associated to this model", + "form_associate_to_plural" => ":attribute associated to this model|:attribute associated to this model", + "form_title_config" => "Setup", + "form_subtitle_config" => "Manage configuration settings.", + "form_title_page" => "Configuration", + "form_subtitle_page" => "Manage the content for a dynamic page.", + "form_title_files" => "Files", + "form_subtitle_files" => "Manage files of the model.", + "form_title_seo" => "SEO fields", + "form_subtitle_seo" => "Manage SEO fields of the model", + "form_title_content" => "Content", + "form_subtitle_content" => "Manage content of the model", + "form_title_configuration" => "Configuration", + "form_subtitle_configuration" => "Manage model configuration.", + "form_title_display" => "Display", + "form_subtitle_display" => "Manage the final display of the model", + "form_title_associations" => "Associations", + "form_subtitle_associations" => "Manage model relationships.", + "form_title_implantation" => "Geographic coordinates", + "form_subtitle_implantation" => "Change the location information for this data model.", + "access_model" => "Access to the :model", + "close" => "Close", + "clear" => "clear", + "config_modal_title" => "Preview", + "config_modal_descripion" => "Contents of the selected configuration", + "config_none_selected" => "No configuration selected", + "config_select_fields" => "Overwrite fields with those of an existing language", + "config_save_warning" => "The configuration of related pages in :locale must be updated accordingly.", + "config_save_warning_list" => "Here is the list of :models concerned:|Here is the list of :models concerned:", + "config_archived" => "This configuration is currently archived", + "config_complete_label" => "Copy the complete label of the input", + "entries_count" => ":length entry filled in|:length entries filled in", + "new_field" => "Add a new field", + "delete_field" => "Delete this field", + "dnd_field" => "Move this field", + "list_children_needed" => "Children are required for this type :enumLabel", + "empty_warning" => "No data recorded", + "page_locked" => "This page is currently locked", + "unsupported_type" => "Unsupported type:", + "missing_translations" => "The translation of the :field for the language :locales is missing.|The translation of the :field for :locales languages are missing.", - "no_more_children" => "Limit reached, you cannot add new items", - "archives" => "archives", - "validate" => "confirm", - "cancel" => "cancel", - "crop" => "crop", - "slugify" => "slugify", - "filter" => "filter|filters", - "image_cropper" => [ + "no_more_children" => "Limit reached, you cannot add new items", + "archives" => "archives", + "validate" => "confirm", + "cancel" => "cancel", + "crop" => "crop", + "slugify" => "slugify", + "filter" => "filter|filters", + "image_cropper" => [ "state_file_uploaded" => "a file is uploaded with success", - "modale_title" => "Image modification", - "modale_description" => "Customize the rendering according to your needs", - "action_the_crop" => ":action the crop", - "select_img_zone" => "Drag and drop an image or click to select one", - "toast" => [ + "modale_title" => "Image modification", + "modale_description" => "Customize the rendering according to your needs", + "action_the_crop" => ":action the crop", + "select_img_zone" => "Drag and drop an image or click to select one", + "toast" => [ "too_big" => "Max size : :maxSize. This file is too big", "no_file" => "no file selected !", "forbidden_file" => "file not allowed.", "too_many" => "the max file allowed exceeded (1)", "defaultError" => "an error occured !" ], - "validation" => [ + "validation" => [ "rules_between" => "media must do :width px width and :height px height.", "rules_weight" => "max size: :size", "allowed_formats" => "allowed formats: :formats" ], - "filters" => [ + "filters" => [ 'zoomIn' => "zoom in", "zoomOut" => "zoom out", "zoom" => "zoom", @@ -154,22 +158,23 @@ return [ "horizontal_flip" => "horizontal flip", ] ], - "multi_select" => [ + "multi_select" => [ "search_options" => "search options...", "select_all" => "select all", "more" => "more", ], - "simple_date_picker" => [ + "simple_date_picker" => [ "reset" => "reset the date" ], - "simple_color_picker" => [ + "simple_color_picker" => [ "select" => "select a color", "reset" => "reset the color", "delete" => "delete the color", ], - "news" => [ + "news" => [ "categories" => [ "placeholder" => "select your article's categories" ] - ] + ], + "implantations" => "implantations", ]; diff --git a/lang/en/front.php b/lang/en/front.php index 1d8204c2..dde0ddab 100644 --- a/lang/en/front.php +++ b/lang/en/front.php @@ -100,5 +100,9 @@ return [ 'newsletter' => [ 'label' => 'I would like to subscribe to the newsletter' ] - ] + ], + 'filter_plants' => 'Filter the sites', + 'pole' => 'Pole', + 'responsible' => 'Responsible', + 'address' => 'Address', ]; diff --git a/lang/en/models.php b/lang/en/models.php index b80bf652..0ab6c2c8 100644 --- a/lang/en/models.php +++ b/lang/en/models.php @@ -8,5 +8,8 @@ return [ "activity-log" => "activity log", "contact-count" => "contact form", "news" => "news|news", + "company" => "company|companies", + "company-activity" => "activity de société|activities de société", + "company-sector" => "company sector|company sectors", ], ]; diff --git a/lang/en/validation.php b/lang/en/validation.php index ae5494e2..aecd9185 100644 --- a/lang/en/validation.php +++ b/lang/en/validation.php @@ -247,18 +247,26 @@ return [ "title" => "seo title", "description" => "seo description", ], - "category" => "category|categories", - "picture" => [ + "category" => "category|categories", + "picture" => [ "picture" => "image", "picture_alt" => "alternative text of the image", "picture_title" => "title image" ], - "content" => "content", + "content" => "content", "contactCount" => [ "type" => "form type", "submissions" => "count of soumissions" ], - "vimeo_id" => "VIMEO ID", - "youtube_id" => "YOUTUBE ID" + "vimeo_id" => "VIMEO ID", + "youtube_id" => "YOUTUBE ID", + "logo" => "logo", + "responsable" => "responsable", + "url" => "url", + "informations" => "informations", + "employees" => "employees", + "latitude" => "latitude", + "longitude" => "longitude", + "color" => "color", ], ]; diff --git a/lang/fr/back.php b/lang/fr/back.php index e8602a77..e97103cd 100644 --- a/lang/fr/back.php +++ b/lang/fr/back.php @@ -1,144 +1,148 @@ "lien de votre page", + "access_to_front_page" => "lien de votre page", "access_to_front_page_when_published" => "lien de votre page une fois publiée", - "login_title" => "Authentification", - "login_desc" => "Connectez-vous afin d'accéder à la partie administrative de votre site + "login_title" => "Authentification", + "login_desc" => "Connectez-vous afin d'accéder à la partie administrative de votre site internet :appName !", - "login_btn" => "Connexion avec UWIL Support", - "login_unpublished_user" => "Votre compte à été désactivé, veuillez contactez un administrateur du site.", - "dashboard" => "Tableau de bord", - "your_website" => "Votre site", - "pages" => "Pages", - "modules" => "Modules", - "telescope" => "Telescope", - "yes_delete" => "Oui, supprimer", - "yes_update" => "Oui, mettre à jour", - "yes_restore" => "Oui, restorer", - "yes_archive" => "Oui, archiver", - "no_cancel" => "Non, annuler", - "yes" => "Oui", - "no" => "Non", - "are_you_sure" => "Êtes-vous sûr ?", - "trash_data" => "Toutes les données seront archivées !", - "restore_data" => "Toutes les données seront restorées !", - "lost_data" => "Toutes les données seront définitivement perdues !", - "model_action_updated_at" => "Dernières modifications le :", - "profile" => "Profil", - "disconnect" => "Se déconnecter", - "sidebar_trigger_tooltip" => "Réduire/aggrandir la barre de navigation", - "warning" => "Attention", - "warning_production" => "Vous êtes actuellement connecté en PRODUCTION. + "login_btn" => "Connexion avec UWIL Support", + "login_unpublished_user" => "Votre compte à été désactivé, veuillez contactez un administrateur du site.", + "dashboard" => "Tableau de bord", + "your_website" => "Votre site", + "pages" => "Pages", + "modules" => "Modules", + "telescope" => "Telescope", + "yes_delete" => "Oui, supprimer", + "yes_update" => "Oui, mettre à jour", + "yes_restore" => "Oui, restorer", + "yes_archive" => "Oui, archiver", + "no_cancel" => "Non, annuler", + "yes" => "Oui", + "no" => "Non", + "are_you_sure" => "Êtes-vous sûr ?", + "trash_data" => "Toutes les données seront archivées !", + "restore_data" => "Toutes les données seront restorées !", + "lost_data" => "Toutes les données seront définitivement perdues !", + "model_action_updated_at" => "Dernières modifications le :", + "profile" => "Profil", + "disconnect" => "Se déconnecter", + "sidebar_trigger_tooltip" => "Réduire/aggrandir la barre de navigation", + "warning" => "Attention", + "warning_production" => "Vous êtes actuellement connecté en PRODUCTION. Pour tester, veuillez vous connecter à la recette !", - "warning_trash" => "Suppression des entrées après 30 jours passé en temps qu'archive !", - "dashboard_paragraph_1" => "Bienvenue dans le back-office de votre site internet + "warning_trash" => "Suppression des entrées après 30 jours passé en temps qu'archive !", + "dashboard_paragraph_1" => "Bienvenue dans le back-office de votre site internet :appName.", - "dashboard_paragraph_2" => "Ici, vous pouvez gérer des contenus apparaissant dans votre site internet, tel que + "dashboard_paragraph_2" => "Ici, vous pouvez gérer des contenus apparaissant dans votre site internet, tel que des images, des textes et bien d'autres éléments.", - "dashboard_paragraph_3" => "UWIL vous accompagne dans votre + "dashboard_paragraph_3" => "UWIL vous accompagne dans votre conception ainsi que la réalisation de vos projets actuels et futurs.", - "dashboard_paragraph_4" => "N'hésitez pas à utiliser nos outils UWIL by LDC :", - "uwil_report_desc" => "Accéder aux statistiques de votre site via notre outil", - "uwil_support_desc" => "Pour tout problème ou évolution souhaitée, veuillez nous contacter via notre outil", - "uwil_expo_desc" => "...", - "uwil_util_tooltip" => "Accéder à notre outil dans un nouvel onglet", - "words" => "Mots : ", - "characters" => "Caractères : ", - "table_no_results" => "Aucun résultat.", - "table_field" => "Champ", - "table_value" => "Valeur", - "table_not_known" => "Non renseigné", - "enter_text_here" => "Renseigner du texte ici", - "enter_number_here" => "Renseigner un chiffre/nombre ici", - "errors" => "Erreurs", - "light" => "Clair", - "dark" => "Sombre", - "system" => "Système", - "mods" => "Modes", - "languages" => "Langues", - "settings" => "Paramètres", - "crud_back_to_list" => "Revenir à la liste des entrées", - "crud_add_entry" => "Ajouter une nouvelle entrée", - "crud_access_trash" => "Accéder aux entrées archivées", - "table_search" => "Rechercher sur :searchFields", - "table_search_reset" => "Effacer la recherche", - "table_filter_button" => "Filtrer les résultats par le champs :field", - "table_filter_reset" => "Retirer tous les filtres sélectionnés", - "form_title_additional_files" => "Fichier supplémentaire", - "form_subtitle_additional_files" => "Ajouter des fichiers supplémentaires", - "form_title_global" => "Informations générales", - "form_subtitle_global" => "Modifier les informations principales liées à ce modèle de données.", - "form_title_visibility" => "Visibilité", - "form_subtitle_visibility" => "Gérer l'affichage du compte.", - "form_title_isLocked" => "Restriction", - "form_subtitle_isLocked" => "Gérer le vérouillage de la page.", - "form_associate_to" => ":attribute associé au modèle|:attribute associée au modèle", - "form_associate_to_plural" => ":attribute associés au modèle|:attribute associées au modèle", - "form_title_config" => "Réglage", - "form_subtitle_config" => "Gérer le paramétrage d'une configuration.", - "form_title_page" => "Configuration", - "form_subtitle_page" => "Gérer le contenu d'une page dynamique.", - "form_title_files" => "Fichiers", - "form_subtitle_files" => "Gérer les fichiers du modèle.", - "form_title_seo" => "Champs SEO", - "form_subtitle_seo" => "Gérer les champs SEO du modèle.", - "form_title_content" => "Contenu", - "form_subtitle_content" => "Gérer le contenu du modèle.", - "form_title_configuration" => "Configuration", - "form_subtitle_configuration" => "Gérer la configuration du modèle.", - "form_title_display" => "Affichage", - "form_subtitle_display" => "Gérer l'ordre d'affichage sur le rendu final.", - "access_model" => "Accéder à la :model", - "clear" => "vider", - "close" => "Fermer", - "config_modal_title" => "Prévisualisation", - "config_modal_descripion" => "Contenu de la configuration sélectionnée", - "config_none_selected" => "Aucune configuration sélectionnée", - "config_select_fields" => "Écraser les champs avec ceux d'une langue déjà existante", - "config_save_warning" => "La configuration des pages associées dans la langue :locale devra être mise à jour + "dashboard_paragraph_4" => "N'hésitez pas à utiliser nos outils UWIL by LDC :", + "uwil_report_desc" => "Accéder aux statistiques de votre site via notre outil", + "uwil_support_desc" => "Pour tout problème ou évolution souhaitée, veuillez nous contacter via notre outil", + "uwil_expo_desc" => "...", + "uwil_util_tooltip" => "Accéder à notre outil dans un nouvel onglet", + "words" => "Mots : ", + "characters" => "Caractères : ", + "table_no_results" => "Aucun résultat.", + "table_field" => "Champ", + "table_value" => "Valeur", + "table_not_known" => "Non renseigné", + "enter_text_here" => "Renseigner du texte ici", + "enter_number_here" => "Renseigner un chiffre/nombre ici", + "errors" => "Erreurs", + "light" => "Clair", + "dark" => "Sombre", + "system" => "Système", + "mods" => "Modes", + "languages" => "Langues", + "settings" => "Paramètres", + "crud_back_to_list" => "Revenir à la liste des entrées", + "crud_add_entry" => "Ajouter une nouvelle entrée", + "crud_access_trash" => "Accéder aux entrées archivées", + "table_search" => "Rechercher sur :searchFields", + "table_search_reset" => "Effacer la recherche", + "table_filter_button" => "Filtrer les résultats par le champs :field", + "table_filter_reset" => "Retirer tous les filtres sélectionnés", + "form_title_additional_files" => "Fichier supplémentaire", + "form_subtitle_additional_files" => "Ajouter des fichiers supplémentaires", + "form_title_global" => "Informations générales", + "form_subtitle_global" => "Modifier les informations principales liées à ce modèle de données.", + "form_title_visibility" => "Visibilité", + "form_subtitle_visibility" => "Gérer l'affichage du compte.", + "form_title_isLocked" => "Restriction", + "form_subtitle_isLocked" => "Gérer le vérouillage de la page.", + "form_associate_to" => ":attribute associé au modèle|:attribute associée au modèle", + "form_associate_to_plural" => ":attribute associés au modèle|:attribute associées au modèle", + "form_title_config" => "Réglage", + "form_subtitle_config" => "Gérer le paramétrage d'une configuration.", + "form_title_page" => "Configuration", + "form_subtitle_page" => "Gérer le contenu d'une page dynamique.", + "form_title_files" => "Fichiers", + "form_subtitle_files" => "Gérer les fichiers du modèle.", + "form_title_seo" => "Champs SEO", + "form_subtitle_seo" => "Gérer les champs SEO du modèle.", + "form_title_content" => "Contenu", + "form_subtitle_content" => "Gérer le contenu du modèle.", + "form_title_configuration" => "Configuration", + "form_subtitle_configuration" => "Gérer la configuration du modèle.", + "form_title_display" => "Affichage", + "form_subtitle_display" => "Gérer l'ordre d'affichage sur le rendu final.", + "form_title_associations" => "Associations", + "form_subtitle_associations" => "Gérer les relations du modèle.", + "form_title_implantation" => "Coordonnées géographiques", + "form_subtitle_implantation" => "Modifiez les informations de localisation de ce modèle de données.", + "access_model" => "Accéder à la :model", + "clear" => "vider", + "close" => "Fermer", + "config_modal_title" => "Prévisualisation", + "config_modal_descripion" => "Contenu de la configuration sélectionnée", + "config_none_selected" => "Aucune configuration sélectionnée", + "config_select_fields" => "Écraser les champs avec ceux d'une langue déjà existante", + "config_save_warning" => "La configuration des pages associées dans la langue :locale devra être mise à jour en conséquence.", - "config_save_warning_list" => "Voici la liste des :models concernés:|Voici la liste des :models concernées:", - "config_archived" => "Cette configuration est actuellement archivée", - "config_complete_label" => "Copier le libellé complet de l'input", - "entries_count" => ":length entrée renseignée|:length entrées renseignées", - "new_field" => "Ajouter un nouveau champ", - "delete_field" => "Supprimer ce champ", - "dnd_field" => "Déplacer ce champ", - "list_children_needed" => "Des enfants sont nécessaires pour ce type :enumLabel", - "empty_warning" => "Aucune donnée enregistrée", - "page_locked" => "Cette page est actuellement vérouillée", - "unsupported_type" => "Type non supporté:", - "missing_translations" => "La traduction du champs :field pour la langue :locales est manquante.|La traduction - du champs :field pour l es langues :locales sont manquantes.", - "no_more_children" => "Limite atteinte, vous ne pouvez pas ajouter de nouveaux éléments", - "archives" => "archives", - "validate" => "valider", - "cancel" => "annuler", - "crop" => "recadrer", - "slugify" => "slugifier", - "filter" => "filtre|filtres", - "image_cropper" => [ + "config_save_warning_list" => "Voici la liste des :models concernés:|Voici la liste des :models concernées:", + "config_archived" => "Cette configuration est actuellement archivée", + "config_complete_label" => "Copier le libellé complet de l'input", + "entries_count" => ":length entrée renseignée|:length entrées renseignées", + "new_field" => "Ajouter un nouveau champ", + "delete_field" => "Supprimer ce champ", + "dnd_field" => "Déplacer ce champ", + "list_children_needed" => "Des enfants sont nécessaires pour ce type :enumLabel", + "empty_warning" => "Aucune donnée enregistrée", + "page_locked" => "Cette page est actuellement vérouillée", + "unsupported_type" => "Type non supporté:", + "missing_translations" => "La traduction du champs :field pour la langue :locales est manquante.|La traduction + du champs :field pour l es langues :locales sont manquantes.", + "no_more_children" => "Limite atteinte, vous ne pouvez pas ajouter de nouveaux éléments", + "archives" => "archives", + "validate" => "valider", + "cancel" => "annuler", + "crop" => "recadrer", + "slugify" => "slugifier", + "filter" => "filtre|filtres", + "image_cropper" => [ "state_file_uploaded" => "un fichier à bien été chargé", - "modale_title" => "Modification de l'image", - "modale_description" => "Personnalisez le rendu selon vos besoins", - "action_the_crop" => ":action le cadrage", - "select_img_zone" => "Glisser-déposer une image ou cliquez pour en sélectionner une", - "toast" => [ + "modale_title" => "Modification de l'image", + "modale_description" => "Personnalisez le rendu selon vos besoins", + "action_the_crop" => ":action le cadrage", + "select_img_zone" => "Glisser-déposer une image ou cliquez pour en sélectionner une", + "toast" => [ "too_big" => "taille maximale autorisée : :maxSize. Le fichier est trop volumineux", "no_file" => "aucun fichier sélectionné !", "forbidden_file" => "fichier non autorisé.", "too_many" => "le nombre de fichier autorisé est dépassé (1)", "defaultError" => "une erreur est survenue !" ], - "validation" => [ + "validation" => [ "rules_between" => "le média doit faire :width px de large et :height px de haut.", "rules_weight" => "taille max: :size", "allowed_formats" => "formats autorisés: :formats", "all_formats" => "tous" ], - "filters" => [ + "filters" => [ 'zoomIn' => "zoom avant", "zoomOut" => "zoom arrière", "zoom" => "zoom", @@ -155,22 +159,23 @@ return [ "horizontal_flip" => "inverser horizontalement", ] ], - "multi_select" => [ + "multi_select" => [ "search_options" => "cherchez parmi les options...", "select_all" => "tout sélectionner", "more" => "supplémentaire(s)", ], - "simple_date_picker" => [ + "simple_date_picker" => [ "reset" => "vider la date", ], - "simple_color_picker" => [ + "simple_color_picker" => [ "select" => "sélectionner une couleur", "reset" => "réinitialiser la couleur", "delete" => "supprimer la couleur", ], - "news" => [ + "news" => [ "categories" => [ "placeholder" => "sélectionnez les catégories de votre article", ] - ] + ], + "implantations" => "implantations", ]; diff --git a/lang/fr/front.php b/lang/fr/front.php index 40ef715d..8039e75b 100644 --- a/lang/fr/front.php +++ b/lang/fr/front.php @@ -100,5 +100,9 @@ return [ 'newsletter' => [ 'label' => 'Je souhaite m’inscrire à la newsletter' ] - ] + ], + 'filter_plants' => 'Filtrer les implantations', + 'pole' => 'Pôle', + 'responsible' => 'Responsable', + 'address' => 'Adresse', ]; diff --git a/lang/fr/models.php b/lang/fr/models.php index fbe60b5e..f22c2b54 100644 --- a/lang/fr/models.php +++ b/lang/fr/models.php @@ -8,5 +8,8 @@ return [ "activity-log" => "journal d'activité", "contact-count" => "formulaire de contact", "news" => "actualité|actualités", + "company" => "société|sociétés", + "company-activity" => "activité de société|activités de société", + "company-sector" => "secteur de société|secteurs de société", ], ]; diff --git a/lang/fr/validation.php b/lang/fr/validation.php index 89c61659..dd90929c 100644 --- a/lang/fr/validation.php +++ b/lang/fr/validation.php @@ -256,7 +256,15 @@ return [ "type" => "type de formulaire", "submissions" => "nombre de soumissions" ], - "vimeo_id" => "ID de la vidéo VIMEO", - "youtube_id" => "ID de la vidéo YOUTUBE" + "vimeo_id" => "ID de la vidéo VIMEO", + "youtube_id" => "ID de la vidéo YOUTUBE", + "logo" => "logo", + "responsable" => "responsable", + "url" => "lien", + "informations" => "informations", + "employees" => "employés", + "latitude" => "latitude", + "longitude" => "longitude", + "color" => "couleur", ], ]; diff --git a/manifest.yaml b/manifest.yaml index efccff30..2aa2e54b 100644 --- a/manifest.yaml +++ b/manifest.yaml @@ -32,6 +32,7 @@ data: GOOGLE_RECAPTCHA_PRIVATE: "${APP_GOOGLE_RECAPTCHA_PRIVATE}" GOOGLE_RECAPTCHA_PUBLIC: "${APP_GOOGLE_RECAPTCHA_PUBLIC}" GOOGLE_RECAPTCHA_VERSION: "${APP_GOOGLE_RECAPTCHA_VERSION}" + GOOGLE_MAPS_KEY: "${APP_GOOGLE_MAPS_KEY}" SAML2_SP_CERT_x509: "${APP_SAML2_SP_CERT_x509}" SAML2_SP_CERT_PRIVATEKEY: "${APP_SAML2_SP_CERT_PRIVATEKEY}" diff --git a/resources/ts/back/Components/Layout/AppSidebar.tsx b/resources/ts/back/Components/Layout/AppSidebar.tsx index ca0362cb..6aa3be1b 100644 --- a/resources/ts/back/Components/Layout/AppSidebar.tsx +++ b/resources/ts/back/Components/Layout/AppSidebar.tsx @@ -13,6 +13,9 @@ import { HistoryIcon, ContactIcon, NewspaperIcon, + Building2Icon, + RadarIcon, + RollerCoasterIcon, } from "lucide-react"; import { route } from "ziggy-js"; // * Components shadcn @@ -128,7 +131,7 @@ export default function AppSidebar() { }, { title: useTrans("back.modules"), - show: authPolicies.dynamicPages.viewAny || authPolicies.pageConfigs.viewAny, + show: authPolicies.news.viewAny || auth.policies.contact_counts.viewAny, links: [ { title: str(useTrans("models.classes.news", { choice: 2 })) @@ -166,6 +169,91 @@ export default function AppSidebar() { }, ], }, + { + title: str(useTrans("back.implantations")).ucFirst().value(), + show: auth.policies.companies.viewAny || auth.policies.companyActivities.viewAny || auth.policies.companySectors.viewAny, + links: [ + { + title: str(useTrans("models.classes.company", { choice: 2 })) + .ucFirst() + .plural() + .value(), + model: "companies", + icon: Building2Icon, + show: auth.policies.companies.viewAny, + actions: (model: string) => filterActions({ + items: [ + authPolicies.companies.create && ( + + ), + authPolicies.companies.viewTrash && ( + + ), + ] + }) + }, + { + title: str(useTrans("models.classes.company-activity", { choice: 2 })) + .ucFirst() + .value(), + model: "company-activities", + icon: RollerCoasterIcon, + show: auth.policies.companyActivities.viewAny, + actions: (model: string) => filterActions({ + items: [ + authPolicies.companyActivities.create && ( + + ), + authPolicies.companyActivities.viewTrash && ( + + ), + ] + }) + }, + { + title: str(useTrans("models.classes.company-sector", { choice: 2 })) + .ucFirst() + .value(), + model: "company-sectors", + icon: RadarIcon, + show: auth.policies.companySectors.viewAny, + actions: (model: string) => filterActions({ + items: [ + authPolicies.companySectors.create && ( + + ), + authPolicies.companySectors.viewTrash && ( + + ), + ] + }) + }, + ], + }, { title: str(useTrans("enums.user-role.admin")).plural().value(), show: auth.user.role === enumUserRole.conceptor.value, diff --git a/resources/ts/back/Pages/Companies/Create.tsx b/resources/ts/back/Pages/Companies/Create.tsx new file mode 100644 index 00000000..14e749e7 --- /dev/null +++ b/resources/ts/back/Pages/Companies/Create.tsx @@ -0,0 +1,57 @@ +// * Packages +import { usePage } from "@inertiajs/react"; +import { route } from "ziggy-js"; +import { ArrowLeftIcon } from "lucide-react"; +// * Other +import AuthenticatedLayout from "@/back/Layouts/AuthenticatedLayout"; +import Form from "@/back/Pages/Companies/Form"; +import BtnOptionnalLinkWithTooltip from "@/back/Components/BtnOptionnalLinkWithTooltip"; +import useTrans from "@/hooks/use-translations"; +import { Actions, Methods } from "@/lib/enums"; +import { + AuthProp, + CompanyModel, + SingleResource, +} from "@/back/types/global"; + +export default function Create({ data }: { data: SingleResource }) { + const { viewAny } = (usePage().props.auth as AuthProp).policies.companies; + const companyModel = data.data as CompanyModel; + const transTitle = useTrans( + route().current(`back.companies.duplicate`) + ? "crud.helpers.duplication_model" + : "crud.helpers.creation_model", + { + params: { + model: useTrans("models.classes.company", { choice: 1 }), + }, + }, + ); + + const beforeNode = () => { + return viewAny && ( +
+ } + tooltipContent={

{useTrans("back.crud_back_to_list")}

} + /> +
+ ); + }; + + return ( + +
+ + ); +} diff --git a/resources/ts/back/Pages/Companies/Edit.tsx b/resources/ts/back/Pages/Companies/Edit.tsx new file mode 100644 index 00000000..3a5694a3 --- /dev/null +++ b/resources/ts/back/Pages/Companies/Edit.tsx @@ -0,0 +1,58 @@ +// * Packages +import { usePage } from "@inertiajs/react"; +import { route } from "ziggy-js"; +import { ArrowLeftIcon } from "lucide-react"; +// * Other +import AuthenticatedLayout from "@/back/Layouts/AuthenticatedLayout"; +import ModelActions from "@/back/Components/ModelActions"; +import Form from "@/back/Pages/Companies/Form"; +import useTrans from "@/hooks/use-translations"; +import { Actions, Methods } from "@/lib/enums"; +import { Views } from "@/lib/utils"; +import { AuthProp, CompanyModel, SingleResource } from "@/back/types/global"; +import BtnOptionnalLinkWithTooltip from "@/back/Components/BtnOptionnalLinkWithTooltip"; + +export default function Edit({ data }: { data: SingleResource }) { + const { viewAny } = (usePage().props.auth as AuthProp).policies.companies; + const companyModel = data.data as CompanyModel; + const actionModels = [ + Views.VISUALIZATION, + Views.DUPLICATION, + Views.ARCHIVATION, + ]; + + const beforeNode = () => { + return viewAny && ( +
+ } + tooltipContent={

{useTrans("back.crud_back_to_list")}

} + /> +
+ ); + }; + + return ( + + + + + ); +} diff --git a/resources/ts/back/Pages/Companies/Form.tsx b/resources/ts/back/Pages/Companies/Form.tsx new file mode 100644 index 00000000..9a1a2a8e --- /dev/null +++ b/resources/ts/back/Pages/Companies/Form.tsx @@ -0,0 +1,317 @@ +// * Packages +import { useForm, usePage } from "@inertiajs/react"; +import { BookTextIcon, EyeIcon, MapPinIcon, RouteIcon } from "lucide-react"; +import { route } from "ziggy-js"; +import { FormEvent } from "react"; +// * Other +import SimpleString from "@/back/Components/Inputs/SimpleString"; +import SimpleNumber from "@/back/Components/Inputs/SimpleNumber"; +import FieldsetWrapper from "@/back/Components/FieldsetWrapper"; +import SimpleSwitch from "@/back/Components/Inputs/SimpleSwitch"; +import CompleteInputFile from "@/back/Components/Inputs/CompleteInputFile"; +import SimpleWysiwyg from "@/back/Components/Inputs/SimpleWysiwyg"; +import ModelSelect from "@/back/Components/Inputs/ModelSelect"; +import BtnOptionnalLinkWithTooltip from "@/back/Components/BtnOptionnalLinkWithTooltip"; +import useTrans from "@/hooks/use-translations"; +import str from "@/hooks/use-string"; +import InputError from "@/back/Components/InputError"; +import { useToast } from "@/hooks/use-toast"; +import { Methods } from "@/lib/enums"; +import { CompanyActivityModel, CompanyModel, CompanySectorModel, DynamicFieldTypes } from "@/back/types/global"; + +export default function Form({ + model, + modelName, + modelRoute, + action, + method, +}: { + model?: CompanyModel; + modelName: string; + modelRoute: string; + action: string; + method: number; +}) { + const enumDynamicFieldTypes = usePage().props.enumDynamicFieldTypes as DynamicFieldTypes; + const companyActivityModels = usePage().props.companyActivityModels as CompanyActivityModel[]; + const companySectorModels = usePage().props.companySectorModels as CompanySectorModel[]; + const { toast } = useToast(); + + /** Set messages success/errors */ + const messages = {} as Record; + messages.titleSuccess = useTrans( + method === Methods.POST ? "Création réussie !" : "Mise à jour réussie !", + ); + messages.descriptionSuccess = str( + useTrans( + method === Methods.POST ? "crud.messages.has_been_created" : "crud.messages.has_been_updated", + { params: { model: useTrans(`models.classes.${modelName}`) } }, + ), + ).ucFirst().value(); + messages.titleError = useTrans( + method === Methods.POST ? "Création annulée !" : "Mise à jour annulée !", + ); + messages.descriptionError = str( + useTrans( + method === Methods.POST ? "crud.messages.cannot_be_created" : "crud.messages.cannot_be_updated", + { params: { model: useTrans(`models.classes.${modelName}`) } }, + ), + ).ucFirst().value(); + + /** Form section */ + const { post, setData, data, reset } = useForm({ + _method: method === Methods.POST ? 'post' : 'put', + name: model?.name, + logo: model?.logo ?? "", + responsable: model?.responsable ?? "", + url: model?.url ?? "", + informations: model?.informations, + employees: model?.employees ?? 0, + latitude: model?.latitude, + longitude: model?.longitude, + activity_id: model?.activity_id, + sector_id: model?.sector_id, + published: model?.published, + }); + const submit = (e: FormEvent) => { + e.preventDefault(); + const routeUrl = route(`back.${modelRoute}.${action}`, model?.id); + if (method !== Methods.PATCH && method !== Methods.POST) throw new Error("The method must be post or patch"); + post(routeUrl, { + preserveScroll: true, + onSuccess: () => { + toast({ + title: messages.titleSuccess, + description: messages.descriptionSuccess, + }); + }, + onError: () => { + toast({ + variant: "destructive", + title: messages.titleError, + description: messages.descriptionError, + }); + }, + }); + }; + + return ( + + + } + description={useTrans("back.form_subtitle_global")} + className="sm:grid-cols-2 gap-4" + > + + + + + + + + } + description={useTrans("back.form_subtitle_associations")} + className="sm:grid-cols-2 gap-4" + > + + + + } + description={useTrans("back.form_subtitle_implantation")} + className="sm:grid-cols-2 gap-4" + > + + + + } + description={useTrans("back.form_subtitle_visibility")} + inline + > + + +
+ +
+ + ); +} diff --git a/resources/ts/back/Pages/Companies/Index.tsx b/resources/ts/back/Pages/Companies/Index.tsx new file mode 100644 index 00000000..f3c3dcbb --- /dev/null +++ b/resources/ts/back/Pages/Companies/Index.tsx @@ -0,0 +1,172 @@ +// * Packages +import { route } from "ziggy-js"; +import { usePage } from "@inertiajs/react"; +import { Row } from "@tanstack/react-table"; +import { AlertCircleIcon, ArchiveIcon, ArrowLeftIcon, CheckIcon, PlusIcon, XIcon } from "lucide-react"; +// * Components shadcn +import { Badge } from "@/components/ui/badge"; +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; +// * Other +import AuthenticatedLayout from "@/back/Layouts/AuthenticatedLayout"; +import DataTable from "@/back/Components/Table/DataTable"; +import DataTableSearch from "@/back/Components/Table/DataTableSearch"; +import DataTableFilterButton from "@/back/Components/Table/DataTableFilterButton"; +import InputError from "@/back/Components/InputError"; +import BtnOptionnalLinkWithTooltip from "@/back/Components/BtnOptionnalLinkWithTooltip"; +import { Views } from "@/lib/utils"; +import { + AuthProp, + CompanyModel, + Resource, +} from "@/back/types/global"; +import str from "@/hooks/use-string"; +import useTrans from "@/hooks/use-translations"; + +export default function Index({ + companyModels, + search, + searchFields, +}: { + companyModels: Resource; + search: string; + searchFields: string; +}) { + const { auth } = usePage().props as unknown as { + auth: AuthProp; + }; + const { viewAny, viewTrash, create } = auth.policies.companies; + const isArchiveRoute = route().current("back.companies.trash"); + const actionModels = isArchiveRoute ? [ + Views.RESTORATION, + Views.FORCEDELETION, + ] : [ + Views.VISUALIZATION, + Views.EDITION, + Views.DUPLICATION, + Views.ARCHIVATION, + ]; + const columns = [ + { + accessorKey: "name", + header: ({ column }: { column: { id: string } }) => ( + + ), + cell: ({ row }: { row: Row }) => row.getValue("name"), + }, + { + accessorKey: "latitude", + header: ({ column }: { column: { id: string } }) => ( + + ), + cell: ({ row }: { row: Row }) => row.getValue("latitude"), + }, + { + accessorKey: "longitude", + header: ({ column }: { column: { id: string } }) => ( + + ), + cell: ({ row }: { row: Row }) => row.getValue("longitude"), + }, + { + accessorKey: "published", + header: ({ column }: { column: { id: string } }) => ( + + ), + cell: ({ row }: { row: Row }) => ( + + {row.getValue("published") ? ( + + ) : ( + + )} + {str(useTrans(row.getValue("published") ? "back.yes" : "back.no")).ucFirst().value()} + + ), + }, + ]; + + const transModel = useTrans("models.classes.company", { choice: 2 }); + const transArchiveTitle = useTrans("crud.helpers.archives_model", { params: { model: transModel }}) + const transTitle = str(isArchiveRoute ? transArchiveTitle : transModel).ucFirst().value(); + + const beforeNode = () => { + return isArchiveRoute && viewAny && ( +
+ } + tooltipContent={

{useTrans("back.crud_back_to_list")}

} + /> +
+ ); + }; + const afterNode = () => { + return !isArchiveRoute && ( +
+ {viewTrash && } + tooltipContent={

{useTrans("back.crud_access_trash")}

} + variant={"outline"} + />} + {create && } + tooltipContent={

{useTrans("back.crud_add_entry")}

} + />} +
+ ); + }; + + return ( + + {isArchiveRoute && ( + <> + + + {useTrans('back.warning')} + +

{useTrans('back.warning_trash')}

+
+
+ + + )} + + +
+ ); +} diff --git a/resources/ts/back/Pages/Companies/Show.tsx b/resources/ts/back/Pages/Companies/Show.tsx new file mode 100644 index 00000000..24055f74 --- /dev/null +++ b/resources/ts/back/Pages/Companies/Show.tsx @@ -0,0 +1,128 @@ +// * Packages +import { usePage } from "@inertiajs/react"; +import { route } from "ziggy-js"; +// * Components shadcn +import { Badge } from "@/components/ui/badge"; +// * Other +import AuthenticatedLayout from "@/back/Layouts/AuthenticatedLayout"; +import DetailsTable from "@/back/Components/Table/DetailsTable"; +import ModelActions from "@/back/Components/ModelActions"; +import { Views } from "@/lib/utils"; +import { useFormatedDate } from "@/hooks/use-formated-value"; +import { + AppEnv, + AuthProp, + CompanyModel, + SingleResource, +} from "@/back/types/global"; +import str from "@/hooks/use-string"; +import useTrans from "@/hooks/use-translations"; +import BtnOptionnalLinkWithTooltip from "@/back/Components/BtnOptionnalLinkWithTooltip"; +import { ArrowLeftIcon } from "lucide-react"; + +export default function Show({ data }: { data: SingleResource }) { + const { auth, appEnv } = usePage().props as unknown as { + auth: AuthProp; + appEnv: AppEnv; + }; + const { viewAny } = auth.policies.companies; + const companyModel = data.data as CompanyModel; + const actionModels = [ + Views.EDITION, + Views.DUPLICATION, + Views.ARCHIVATION, + ]; + const columns = [ + { + accessorKey: "name", + header: str(useTrans("validation.attributes.name")).ucFirst().value(), + cell: ({ value }: { value: string }) => value, + }, + { + accessorKey: "logo", + header: str(useTrans("validation.custom.logo")).ucFirst().value(), + cell: ({ value }: { value: string }) => value, + }, + { + accessorKey: "responsable", + header: str(useTrans("validation.custom.responsable")).ucFirst().value(), + cell: ({ value }: { value: string }) => value, + }, + { + accessorKey: "url", + header: str(useTrans("validation.custom.url")).ucFirst().value(), + cell: ({ value }: { value: string }) => value, + }, + { + accessorKey: "informations", + header: str(useTrans("validation.custom.informations")).ucFirst().value(), + cell: ({ value }: { value: string }) => value, + }, + { + accessorKey: "employees", + header: str(useTrans("validation.custom.employees")).ucFirst().value(), + cell: ({ value }: { value: number }) => value, + }, + { + accessorKey: "latitude", + header: str(useTrans("validation.custom.latitude")).ucFirst().value(), + cell: ({ value }: { value: number }) => value, + }, + { + accessorKey: "longitude", + header: str(useTrans("validation.custom.longitude")).ucFirst().value(), + cell: ({ value }: { value: number }) => value, + }, + { + accessorKey: "created_at", + header: str(useTrans("validation.attributes.created_at")).ucFirst().value(), + cell: ({ value }: { value: string }) => ( + {useFormatedDate(value)} + ), + }, + { + accessorKey: "updated_at", + header: str(useTrans("validation.attributes.updated_at")).ucFirst().value(), + cell: ({ value }: { value: string }) => ( + {useFormatedDate(value)} + ), + }, + { + accessorKey: "deleted_at", + header: str(useTrans("validation.attributes.deleted_at")).ucFirst().value(), + cell: ({ value }: { value: string }) => ( + {useFormatedDate(value)} + ), + }, + ]; + + const beforeNode = () => { + return viewAny && ( +
+ } + tooltipContent={

{useTrans("back.crud_back_to_list")}

} + /> +
+ ); + }; + + return ( + + + {/* @ts-expect-error Weird error type on cell. */} + + + ); +} diff --git a/resources/ts/back/Pages/CompanyActivities/Create.tsx b/resources/ts/back/Pages/CompanyActivities/Create.tsx new file mode 100644 index 00000000..339d707f --- /dev/null +++ b/resources/ts/back/Pages/CompanyActivities/Create.tsx @@ -0,0 +1,57 @@ +// * Packages +import { usePage } from "@inertiajs/react"; +import { route } from "ziggy-js"; +import { ArrowLeftIcon } from "lucide-react"; +// * Other +import AuthenticatedLayout from "@/back/Layouts/AuthenticatedLayout"; +import Form from "@/back/Pages/CompanyActivities/Form"; +import BtnOptionnalLinkWithTooltip from "@/back/Components/BtnOptionnalLinkWithTooltip"; +import useTrans from "@/hooks/use-translations"; +import { Actions, Methods } from "@/lib/enums"; +import { + AuthProp, + CompanyActivityModel, + SingleResource, +} from "@/back/types/global"; + +export default function Create({ data }: { data: SingleResource }) { + const { viewAny } = (usePage().props.auth as AuthProp).policies.companyActivities; + const companyActivityModel = data.data as CompanyActivityModel; + const transTitle = useTrans( + route().current(`back.company-activities.duplicate`) + ? "crud.helpers.duplication_model" + : "crud.helpers.creation_model", + { + params: { + model: useTrans("models.classes.company-activity", { choice: 1 }), + }, + }, + ); + + const beforeNode = () => { + return viewAny && ( +
+ } + tooltipContent={

{useTrans("back.crud_back_to_list")}

} + /> +
+ ); + }; + + return ( + +
+ + ); +} diff --git a/resources/ts/back/Pages/CompanyActivities/Edit.tsx b/resources/ts/back/Pages/CompanyActivities/Edit.tsx new file mode 100644 index 00000000..2805728c --- /dev/null +++ b/resources/ts/back/Pages/CompanyActivities/Edit.tsx @@ -0,0 +1,58 @@ +// * Packages +import { usePage } from "@inertiajs/react"; +import { route } from "ziggy-js"; +import { ArrowLeftIcon } from "lucide-react"; +// * Other +import AuthenticatedLayout from "@/back/Layouts/AuthenticatedLayout"; +import ModelActions from "@/back/Components/ModelActions"; +import Form from "@/back/Pages/CompanyActivities/Form"; +import useTrans from "@/hooks/use-translations"; +import { Actions, Methods } from "@/lib/enums"; +import { Views } from "@/lib/utils"; +import { AuthProp, CompanyActivityModel, SingleResource } from "@/back/types/global"; +import BtnOptionnalLinkWithTooltip from "@/back/Components/BtnOptionnalLinkWithTooltip"; + +export default function Edit({ data }: { data: SingleResource }) { + const { viewAny } = (usePage().props.auth as AuthProp).policies.companyActivities; + const companyActivityModel = data.data as CompanyActivityModel; + const actionModels = [ + Views.VISUALIZATION, + Views.DUPLICATION, + Views.ARCHIVATION, + ]; + + const beforeNode = () => { + return viewAny && ( +
+ } + tooltipContent={

{useTrans("back.crud_back_to_list")}

} + /> +
+ ); + }; + + return ( + + + + + ); +} diff --git a/resources/ts/back/Pages/CompanyActivities/Form.tsx b/resources/ts/back/Pages/CompanyActivities/Form.tsx new file mode 100644 index 00000000..f1108808 --- /dev/null +++ b/resources/ts/back/Pages/CompanyActivities/Form.tsx @@ -0,0 +1,160 @@ +// * Packages +import { useForm, usePage } from "@inertiajs/react"; +import { BookTextIcon, EyeIcon } from "lucide-react"; +import { route } from "ziggy-js"; +import { FormEvent } from "react"; +// * Other +import SimpleString from "@/back/Components/Inputs/SimpleString"; +import FieldsetWrapper from "@/back/Components/FieldsetWrapper"; +import SimpleSwitch from "@/back/Components/Inputs/SimpleSwitch"; +import SimpleColorPicker from "@/back/Components/Inputs/SimpleColorPicker"; +import BtnOptionnalLinkWithTooltip from "@/back/Components/BtnOptionnalLinkWithTooltip"; +import useTrans from "@/hooks/use-translations"; +import str from "@/hooks/use-string"; +import InputError from "@/back/Components/InputError"; +import { useToast } from "@/hooks/use-toast"; +import { Methods } from "@/lib/enums"; +import { AppEnv, CompanyActivityModel } from "@/back/types/global"; + +export default function Form({ + model, + modelName, + modelRoute, + action, + method, +}: { + model?: CompanyActivityModel; + modelName: string; + modelRoute: string; + action: string; + method: number; +}) { + const { locale } = usePage().props.appEnv as AppEnv; + const { toast } = useToast(); + + /** Set messages success/errors */ + const messages = {} as Record; + messages.titleSuccess = useTrans( + method === Methods.POST ? "Création réussie !" : "Mise à jour réussie !", + ); + messages.descriptionSuccess = str( + useTrans( + method === Methods.POST ? "crud.messages.has_been_created" : "crud.messages.has_been_updated", + { params: { model: useTrans(`models.classes.${modelName}`, { choice: 1 }) } }, + ), + ).ucFirst().value(); + messages.titleError = useTrans( + method === Methods.POST ? "Création annulée !" : "Mise à jour annulée !", + ); + messages.descriptionError = str( + useTrans( + method === Methods.POST ? "crud.messages.cannot_be_created" : "crud.messages.cannot_be_updated", + { params: { model: useTrans(`models.classes.${modelName}`, { choice: 1 }) } }, + ), + ).ucFirst().value(); + + /** Form section */ + const { post, patch, setData, data } = useForm({ + name: model?.name ? model?.name[locale] : "", + color: model?.color ?? null, + published: model?.published, + }); + const routeOptions = () => { + return { + preserveScroll: true, + onSuccess: () => { + toast({ + title: messages.titleSuccess, + description: messages.descriptionSuccess, + }); + }, + onError: () => { + toast({ + variant: "destructive", + title: messages.titleError, + description: messages.descriptionError, + }); + }, + }; + }; + const submit = (e: FormEvent) => { + e.preventDefault(); + const routeUrl = route(`back.${modelRoute}.${action}`, model?.id); + switch (method) { + case Methods.POST: + post(routeUrl, routeOptions()); + break; + case Methods.PATCH: + patch(routeUrl, routeOptions()); + break; + default: + throw new Error("The method must be post or patch"); + } + }; + + return ( + + + } + description={useTrans("back.form_subtitle_global")} + className="sm:grid-cols-2 gap-4" + > + + + + } + description={useTrans("back.form_subtitle_visibility")} + inline + > + + +
+ +
+ + ); +} diff --git a/resources/ts/back/Pages/CompanyActivities/Index.tsx b/resources/ts/back/Pages/CompanyActivities/Index.tsx new file mode 100644 index 00000000..64f65ff1 --- /dev/null +++ b/resources/ts/back/Pages/CompanyActivities/Index.tsx @@ -0,0 +1,181 @@ +// * Packages +import { route } from "ziggy-js"; +import { usePage } from "@inertiajs/react"; +import { Row } from "@tanstack/react-table"; +import { AlertCircleIcon, ArchiveIcon, ArrowLeftIcon, CheckIcon, PlusIcon, XIcon } from "lucide-react"; +// * Components shadcn +import { Badge } from "@/components/ui/badge"; +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; +import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; +// * Other +import AuthenticatedLayout from "@/back/Layouts/AuthenticatedLayout"; +import DataTable from "@/back/Components/Table/DataTable"; +import DataTableSearch from "@/back/Components/Table/DataTableSearch"; +import DataTableFilterButton from "@/back/Components/Table/DataTableFilterButton"; +import InputError from "@/back/Components/InputError"; +import BtnOptionnalLinkWithTooltip from "@/back/Components/BtnOptionnalLinkWithTooltip"; +import { Views } from "@/lib/utils"; +import { + AppEnv, + AuthProp, + CompanyActivityModel, + Resource, + TranslationField, +} from "@/back/types/global"; +import str from "@/hooks/use-string"; +import useTrans from "@/hooks/use-translations"; + +export default function Index({ + companyActivityModels, + search, + searchFields, +}: { + companyActivityModels: Resource; + search: string; + searchFields: string; +}) { + const { auth, appEnv } = usePage().props as unknown as { + auth: AuthProp; + appEnv: AppEnv; + }; + const { viewAny, viewTrash, create } = auth.policies.companyActivities; + const isArchiveRoute = route().current("back.company-activities.trash"); + const actionModels = isArchiveRoute ? [ + Views.RESTORATION, + Views.FORCEDELETION, + ] : [ + Views.VISUALIZATION, + Views.EDITION, + Views.DUPLICATION, + Views.ARCHIVATION, + ]; + const columns = [ + { + accessorKey: "name", + header: ({ column }: { column: { id: string } }) => ( + + ), + cell: ({ row }: { row: Row }) => { + return (row.getValue("name") as TranslationField)[appEnv.locale] ? ( + (row.getValue("name") as TranslationField)[appEnv.locale] + ) : (

{useTrans('back.table_not_known')}

); + }, + }, + { + accessorKey: "color", + header: ({ column }: { column: { id: string } }) => ( + + ), + cell: ({ row }: { row: Row }) => { + return ( + + +
+
+ {row.getValue("color")} +
+ ) + }, + }, + { + accessorKey: "published", + header: ({ column }: { column: { id: string } }) => ( + + ), + cell: ({ row }: { row: Row }) => ( + + {row.getValue("published") ? ( + + ) : ( + + )} + {str(useTrans(row.getValue("published") ? "back.yes" : "back.no")).ucFirst().value()} + + ), + }, + ]; + + const transModel = useTrans("models.classes.company-activity", { choice: 2 }); + const transArchiveTitle = useTrans("crud.helpers.archives_model", { params: { model: transModel }}) + const transTitle = str(isArchiveRoute ? transArchiveTitle : transModel).ucFirst().value(); + + const beforeNode = () => { + return isArchiveRoute && viewAny && ( +
+ } + tooltipContent={

{useTrans("back.crud_back_to_list")}

} + /> +
+ ); + }; + const afterNode = () => { + return !isArchiveRoute && ( +
+ {viewTrash && } + tooltipContent={

{useTrans("back.crud_access_trash")}

} + variant={"outline"} + />} + {create && } + tooltipContent={

{useTrans("back.crud_add_entry")}

} + />} +
+ ); + }; + + return ( + + {isArchiveRoute && ( + <> + + + {useTrans('back.warning')} + +

{useTrans('back.warning_trash')}

+
+
+ + + )} + + +
+ ); +} diff --git a/resources/ts/back/Pages/CompanyActivities/Show.tsx b/resources/ts/back/Pages/CompanyActivities/Show.tsx new file mode 100644 index 00000000..27e98c15 --- /dev/null +++ b/resources/ts/back/Pages/CompanyActivities/Show.tsx @@ -0,0 +1,120 @@ +// * Packages +import { usePage } from "@inertiajs/react"; +import { route } from "ziggy-js"; +// * Components shadcn +import { Badge } from "@/components/ui/badge"; +// * Other +import AuthenticatedLayout from "@/back/Layouts/AuthenticatedLayout"; +import DetailsTable from "@/back/Components/Table/DetailsTable"; +import ModelActions from "@/back/Components/ModelActions"; +import { Views } from "@/lib/utils"; +import { useFormatedDate } from "@/hooks/use-formated-value"; +import { + AppEnv, + AuthProp, + CompanyActivityModel, + SingleResource, + TranslationField, +} from "@/back/types/global"; +import str from "@/hooks/use-string"; +import useTrans from "@/hooks/use-translations"; +import BtnOptionnalLinkWithTooltip from "@/back/Components/BtnOptionnalLinkWithTooltip"; +import { ArrowLeftIcon, CheckIcon, XIcon } from "lucide-react"; + +export default function Show({ data }: { data: SingleResource }) { + const { auth, appEnv } = usePage().props as unknown as { + auth: AuthProp; + appEnv: AppEnv; + }; + const { viewAny } = auth.policies.companyActivities; + const companyActivityModel = data.data as CompanyActivityModel; + const actionModels = [ + Views.EDITION, + Views.DUPLICATION, + Views.ARCHIVATION, + ]; + const columns = [ + { + accessorKey: "name", + header: str(useTrans("validation.attributes.name")).ucFirst().value(), + cell: ({ value }: { value: TranslationField }) => value[appEnv.locale] + ? value[appEnv.locale] + : (

{useTrans('back.table_not_known')}

), + }, + { + accessorKey: "color", + header: str(useTrans("validation.custom.color")).ucFirst().value(), + cell: ({ value }: { value: string }) => value, + }, + { + accessorKey: "created_at", + header: str(useTrans("validation.attributes.created_at")).ucFirst().value(), + cell: ({ value }: { value: string }) => ( + {useFormatedDate(value)} + ), + }, + { + accessorKey: "published", + header: str(useTrans("validation.custom.published")).ucFirst().value(), + cell: ({ value }: { value: boolean }) => ( + + {value ? ( + + ) : ( + + )} + {str(useTrans(value ? "back.yes" : "back.no")).ucFirst().value()} + + ), + }, + { + accessorKey: "updated_at", + header: str(useTrans("validation.attributes.updated_at")).ucFirst().value(), + cell: ({ value }: { value: string }) => ( + {useFormatedDate(value)} + ), + }, + { + accessorKey: "deleted_at", + header: str(useTrans("validation.attributes.deleted_at")).ucFirst().value(), + cell: ({ value }: { value: string }) => ( + {useFormatedDate(value)} + ), + }, + ]; + + const beforeNode = () => { + return viewAny && ( +
+ } + tooltipContent={

{useTrans("back.crud_back_to_list")}

} + /> +
+ ); + }; + + return ( + + + {/* @ts-expect-error Weird error type on cell. */} + + + ); +} diff --git a/resources/ts/back/Pages/CompanySectors/Create.tsx b/resources/ts/back/Pages/CompanySectors/Create.tsx new file mode 100644 index 00000000..f4fcd01b --- /dev/null +++ b/resources/ts/back/Pages/CompanySectors/Create.tsx @@ -0,0 +1,57 @@ +// * Packages +import { usePage } from "@inertiajs/react"; +import { route } from "ziggy-js"; +import { ArrowLeftIcon } from "lucide-react"; +// * Other +import AuthenticatedLayout from "@/back/Layouts/AuthenticatedLayout"; +import Form from "@/back/Pages/CompanySectors/Form"; +import BtnOptionnalLinkWithTooltip from "@/back/Components/BtnOptionnalLinkWithTooltip"; +import useTrans from "@/hooks/use-translations"; +import { Actions, Methods } from "@/lib/enums"; +import { + AuthProp, + CompanySectorModel, + SingleResource, +} from "@/back/types/global"; + +export default function Create({ data }: { data: SingleResource }) { + const { viewAny } = (usePage().props.auth as AuthProp).policies.companySectors; + const companySectorModel = data.data as CompanySectorModel; + const transTitle = useTrans( + route().current(`back.company-sectors.duplicate`) + ? "crud.helpers.duplication_model" + : "crud.helpers.creation_model", + { + params: { + model: useTrans("models.classes.company-sector", { choice: 1 }), + }, + }, + ); + + const beforeNode = () => { + return viewAny && ( +
+ } + tooltipContent={

{useTrans("back.crud_back_to_list")}

} + /> +
+ ); + }; + + return ( + +
+ + ); +} diff --git a/resources/ts/back/Pages/CompanySectors/Edit.tsx b/resources/ts/back/Pages/CompanySectors/Edit.tsx new file mode 100644 index 00000000..c8f5131d --- /dev/null +++ b/resources/ts/back/Pages/CompanySectors/Edit.tsx @@ -0,0 +1,58 @@ +// * Packages +import { usePage } from "@inertiajs/react"; +import { route } from "ziggy-js"; +import { ArrowLeftIcon } from "lucide-react"; +// * Other +import AuthenticatedLayout from "@/back/Layouts/AuthenticatedLayout"; +import ModelActions from "@/back/Components/ModelActions"; +import Form from "@/back/Pages/CompanySectors/Form"; +import useTrans from "@/hooks/use-translations"; +import { Actions, Methods } from "@/lib/enums"; +import { Views } from "@/lib/utils"; +import { AuthProp, CompanySectorModel, SingleResource } from "@/back/types/global"; +import BtnOptionnalLinkWithTooltip from "@/back/Components/BtnOptionnalLinkWithTooltip"; + +export default function Edit({ data }: { data: SingleResource }) { + const { viewAny } = (usePage().props.auth as AuthProp).policies.companySectors; + const companySectorModel = data.data as CompanySectorModel; + const actionModels = [ + Views.VISUALIZATION, + Views.DUPLICATION, + Views.ARCHIVATION, + ]; + + const beforeNode = () => { + return viewAny && ( +
+ } + tooltipContent={

{useTrans("back.crud_back_to_list")}

} + /> +
+ ); + }; + + return ( + + + + + ); +} diff --git a/resources/ts/back/Pages/CompanySectors/Form.tsx b/resources/ts/back/Pages/CompanySectors/Form.tsx new file mode 100644 index 00000000..ba0782dc --- /dev/null +++ b/resources/ts/back/Pages/CompanySectors/Form.tsx @@ -0,0 +1,144 @@ +// * Packages +import { useForm, usePage } from "@inertiajs/react"; +import { BookTextIcon, EyeIcon } from "lucide-react"; +import { route } from "ziggy-js"; +import { FormEvent } from "react"; +// * Other +import SimpleString from "@/back/Components/Inputs/SimpleString"; +import FieldsetWrapper from "@/back/Components/FieldsetWrapper"; +import SimpleSwitch from "@/back/Components/Inputs/SimpleSwitch"; +import BtnOptionnalLinkWithTooltip from "@/back/Components/BtnOptionnalLinkWithTooltip"; +import useTrans from "@/hooks/use-translations"; +import str from "@/hooks/use-string"; +import InputError from "@/back/Components/InputError"; +import { useToast } from "@/hooks/use-toast"; +import { Methods } from "@/lib/enums"; +import { AppEnv, CompanySectorModel } from "@/back/types/global"; + +export default function Form({ + model, + modelName, + modelRoute, + action, + method, +}: { + model?: CompanySectorModel; + modelName: string; + modelRoute: string; + action: string; + method: number; +}) { + const { locale } = usePage().props.appEnv as AppEnv; + const { toast } = useToast(); + + /** Set messages success/errors */ + const messages = {} as Record; + messages.titleSuccess = useTrans( + method === Methods.POST ? "Création réussie !" : "Mise à jour réussie !", + ); + messages.descriptionSuccess = str( + useTrans( + method === Methods.POST ? "crud.messages.has_been_created" : "crud.messages.has_been_updated", + { params: { model: useTrans(`models.classes.${modelName}`, { choice: 1 }) } }, + ), + ).ucFirst().value(); + messages.titleError = useTrans( + method === Methods.POST ? "Création annulée !" : "Mise à jour annulée !", + ); + messages.descriptionError = str( + useTrans( + method === Methods.POST ? "crud.messages.cannot_be_created" : "crud.messages.cannot_be_updated", + { params: { model: useTrans(`models.classes.${modelName}`, { choice: 1 }) } }, + ), + ).ucFirst().value(); + + /** Form section */ + const { post, patch, setData, data } = useForm({ + name: model?.name ? model?.name[locale] : "", + published: model?.published, + }); + const routeOptions = () => { + return { + preserveScroll: true, + onSuccess: () => { + toast({ + title: messages.titleSuccess, + description: messages.descriptionSuccess, + }); + }, + onError: () => { + toast({ + variant: "destructive", + title: messages.titleError, + description: messages.descriptionError, + }); + }, + }; + }; + const submit = (e: FormEvent) => { + e.preventDefault(); + const routeUrl = route(`back.${modelRoute}.${action}`, model?.id); + switch (method) { + case Methods.POST: + post(routeUrl, routeOptions()); + break; + case Methods.PATCH: + patch(routeUrl, routeOptions()); + break; + default: + throw new Error("The method must be post or patch"); + } + }; + + return ( + + + } + description={useTrans("back.form_subtitle_global")} + className="sm:grid-cols-2 gap-4" + > + + + } + description={useTrans("back.form_subtitle_visibility")} + inline + > + + +
+ +
+ + ); +} diff --git a/resources/ts/back/Pages/CompanySectors/Index.tsx b/resources/ts/back/Pages/CompanySectors/Index.tsx new file mode 100644 index 00000000..c27cf389 --- /dev/null +++ b/resources/ts/back/Pages/CompanySectors/Index.tsx @@ -0,0 +1,159 @@ +// * Packages +import { route } from "ziggy-js"; +import { usePage } from "@inertiajs/react"; +import { Row } from "@tanstack/react-table"; +import { AlertCircleIcon, ArchiveIcon, ArrowLeftIcon, CheckIcon, PlusIcon, XIcon } from "lucide-react"; +// * Components shadcn +import { Badge } from "@/components/ui/badge"; +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; +// * Other +import AuthenticatedLayout from "@/back/Layouts/AuthenticatedLayout"; +import DataTable from "@/back/Components/Table/DataTable"; +import DataTableSearch from "@/back/Components/Table/DataTableSearch"; +import DataTableFilterButton from "@/back/Components/Table/DataTableFilterButton"; +import InputError from "@/back/Components/InputError"; +import BtnOptionnalLinkWithTooltip from "@/back/Components/BtnOptionnalLinkWithTooltip"; +import { Views } from "@/lib/utils"; +import { + AppEnv, + AuthProp, + CompanySectorModel, + Resource, + TranslationField, +} from "@/back/types/global"; +import str from "@/hooks/use-string"; +import useTrans from "@/hooks/use-translations"; + +export default function Index({ + companySectorModels, + search, + searchFields, +}: { + companySectorModels: Resource; + search: string; + searchFields: string; +}) { + const { auth, appEnv } = usePage().props as unknown as { + auth: AuthProp; + appEnv: AppEnv; + }; + const { viewAny, viewTrash, create } = auth.policies.companySectors; + const isArchiveRoute = route().current("back.company-sectors.trash"); + const actionModels = isArchiveRoute ? [ + Views.RESTORATION, + Views.FORCEDELETION, + ] : [ + Views.VISUALIZATION, + Views.EDITION, + Views.DUPLICATION, + Views.ARCHIVATION, + ]; + const columns = [ + { + accessorKey: "name", + header: ({ column }: { column: { id: string } }) => ( + + ), + cell: ({ row }: { row: Row }) => { + return (row.getValue("name") as TranslationField)[appEnv.locale] ? ( + (row.getValue("name") as TranslationField)[appEnv.locale] + ) : (

{useTrans('back.table_not_known')}

); + }, + }, + { + accessorKey: "published", + header: ({ column }: { column: { id: string } }) => ( + + ), + cell: ({ row }: { row: Row }) => ( + + {row.getValue("published") ? ( + + ) : ( + + )} + {str(useTrans(row.getValue("published") ? "back.yes" : "back.no")).ucFirst().value()} + + ), + }, + ]; + + const transModel = useTrans("models.classes.company-sector", { choice: 2 }); + const transArchiveTitle = useTrans("crud.helpers.archives_model", { params: { model: transModel }}) + const transTitle = str(isArchiveRoute ? transArchiveTitle : transModel).ucFirst().value(); + + const beforeNode = () => { + return isArchiveRoute && viewAny && ( +
+ } + tooltipContent={

{useTrans("back.crud_back_to_list")}

} + /> +
+ ); + }; + const afterNode = () => { + return !isArchiveRoute && ( +
+ {viewTrash && } + tooltipContent={

{useTrans("back.crud_access_trash")}

} + variant={"outline"} + />} + {create && } + tooltipContent={

{useTrans("back.crud_add_entry")}

} + />} +
+ ); + }; + + return ( + + {isArchiveRoute && ( + <> + + + {useTrans('back.warning')} + +

{useTrans('back.warning_trash')}

+
+
+ + + )} + + +
+ ); +} diff --git a/resources/ts/back/Pages/CompanySectors/Show.tsx b/resources/ts/back/Pages/CompanySectors/Show.tsx new file mode 100644 index 00000000..1b67e762 --- /dev/null +++ b/resources/ts/back/Pages/CompanySectors/Show.tsx @@ -0,0 +1,115 @@ +// * Packages +import { usePage } from "@inertiajs/react"; +import { route } from "ziggy-js"; +// * Components shadcn +import { Badge } from "@/components/ui/badge"; +// * Other +import AuthenticatedLayout from "@/back/Layouts/AuthenticatedLayout"; +import DetailsTable from "@/back/Components/Table/DetailsTable"; +import ModelActions from "@/back/Components/ModelActions"; +import { Views } from "@/lib/utils"; +import { useFormatedDate } from "@/hooks/use-formated-value"; +import { + AppEnv, + AuthProp, + CompanySectorModel, + SingleResource, + TranslationField, +} from "@/back/types/global"; +import str from "@/hooks/use-string"; +import useTrans from "@/hooks/use-translations"; +import BtnOptionnalLinkWithTooltip from "@/back/Components/BtnOptionnalLinkWithTooltip"; +import { ArrowLeftIcon, CheckIcon, XIcon } from "lucide-react"; + +export default function Show({ data }: { data: SingleResource }) { + const { auth, appEnv } = usePage().props as unknown as { + auth: AuthProp; + appEnv: AppEnv; + }; + const { viewAny } = auth.policies.companySectors; + const companySectorModel = data.data as CompanySectorModel; + const actionModels = [ + Views.EDITION, + Views.DUPLICATION, + Views.ARCHIVATION, + ]; + const columns = [ + { + accessorKey: "name", + header: str(useTrans("validation.attributes.name")).ucFirst().value(), + cell: ({ value }: { value: TranslationField }) => value[appEnv.locale] + ? value[appEnv.locale] + : (

{useTrans('back.table_not_known')}

), + }, + { + accessorKey: "published", + header: str(useTrans("validation.custom.published")).ucFirst().value(), + cell: ({ value }: { value: boolean }) => ( + + {value ? ( + + ) : ( + + )} + {str(useTrans(value ? "back.yes" : "back.no")).ucFirst().value()} + + ), + }, + { + accessorKey: "created_at", + header: str(useTrans("validation.attributes.created_at")).ucFirst().value(), + cell: ({ value }: { value: string }) => ( + {useFormatedDate(value)} + ), + }, + { + accessorKey: "updated_at", + header: str(useTrans("validation.attributes.updated_at")).ucFirst().value(), + cell: ({ value }: { value: string }) => ( + {useFormatedDate(value)} + ), + }, + { + accessorKey: "deleted_at", + header: str(useTrans("validation.attributes.deleted_at")).ucFirst().value(), + cell: ({ value }: { value: string }) => ( + {useFormatedDate(value)} + ), + }, + ]; + + const beforeNode = () => { + return viewAny && ( +
+ } + tooltipContent={

{useTrans("back.crud_back_to_list")}

} + /> +
+ ); + }; + + return ( + + + {/* @ts-expect-error Weird error type on cell. */} + + + ); +} diff --git a/resources/ts/back/Pages/DynamicPages/Form.tsx b/resources/ts/back/Pages/DynamicPages/Form.tsx index 3f600404..307a084a 100644 --- a/resources/ts/back/Pages/DynamicPages/Form.tsx +++ b/resources/ts/back/Pages/DynamicPages/Form.tsx @@ -327,7 +327,6 @@ export default function Form({ type="button" variant="secondary" onClick={() => { - console.log("test"); setData("slug", str(data.title).slug().value()); }} /> diff --git a/resources/ts/back/types/global.d.ts b/resources/ts/back/types/global.d.ts index cbe87222..2c26b4cc 100644 --- a/resources/ts/back/types/global.d.ts +++ b/resources/ts/back/types/global.d.ts @@ -132,6 +132,43 @@ type NewsCategoryModel = { category: number; } +type CompanyModel = { + id: number; + name: string; + logo: string; + responsable: string; + url: string; + informations: string; + employees: number; + latitude: number; + longitude: number; + activity_id: number; + sector_id: number|null; + published: boolean; + created_at: Date; + updated_at: Date; + deleted_at: Date; +} + +type CompanyActivityModel = { + id: number; + name: TranslationField; + color: string; + published: boolean; + created_at: Date; + updated_at: Date; + deleted_at: Date; +} + +type CompanySectorModel = { + id: number; + name: TranslationField; + published: boolean; + created_at: Date; + updated_at: Date; + deleted_at: Date; +} + // Default model, with policies. type DefaultModel = { policies: ModelPolicy; @@ -147,7 +184,10 @@ type Model = | PageConfigModel | DynamicPageModel | NewsModel - | ActivityLogModel; + | ActivityLogModel + | CompanyModel + | CompanyActivityModel + | CompanySectorModel; // Common policy type. type CommonPolicy = { diff --git a/resources/views/components/front/pages/join-us/join-us.blade.php b/resources/views/components/front/pages/join-us/join-us.blade.php index e511ea6f..bbcb169c 100644 --- a/resources/views/components/front/pages/join-us/join-us.blade.php +++ b/resources/views/components/front/pages/join-us/join-us.blade.php @@ -53,7 +53,8 @@
- +
diff --git a/resources/views/components/front/pages/join-us/our-politics.blade.php b/resources/views/components/front/pages/join-us/our-politics.blade.php index f417d2be..11eef0d2 100644 --- a/resources/views/components/front/pages/join-us/our-politics.blade.php +++ b/resources/views/components/front/pages/join-us/our-politics.blade.php @@ -52,7 +52,7 @@ NOTRE POLITIQUE
- +
diff --git a/resources/views/components/front/pages/join-us/our-professions.blade.php b/resources/views/components/front/pages/join-us/our-professions.blade.php index 89f5b4f0..59c3326c 100644 --- a/resources/views/components/front/pages/join-us/our-professions.blade.php +++ b/resources/views/components/front/pages/join-us/our-professions.blade.php @@ -261,7 +261,8 @@
- +

{{ $professions['text'] }}

 

diff --git a/resources/views/components/front/pages/join-us/your-career.blade.php b/resources/views/components/front/pages/join-us/your-career.blade.php index 82e23f82..7f68f77f 100644 --- a/resources/views/components/front/pages/join-us/your-career.blade.php +++ b/resources/views/components/front/pages/join-us/your-career.blade.php @@ -99,7 +99,8 @@
- +
VOTRE PARCOURS
diff --git a/resources/views/components/front/pages/known-us/historic-slider.blade.php b/resources/views/components/front/pages/know-us/historic-slider.blade.php similarity index 100% rename from resources/views/components/front/pages/known-us/historic-slider.blade.php rename to resources/views/components/front/pages/know-us/historic-slider.blade.php diff --git a/resources/views/components/front/pages/known-us/historical.blade.php b/resources/views/components/front/pages/know-us/historical.blade.php similarity index 65% rename from resources/views/components/front/pages/known-us/historical.blade.php rename to resources/views/components/front/pages/know-us/historical.blade.php index 353f6aa1..6b5766da 100644 --- a/resources/views/components/front/pages/known-us/historical.blade.php +++ b/resources/views/components/front/pages/know-us/historical.blade.php @@ -3,10 +3,10 @@

{{ $ourHistory['string_title'] }}

- +
{!! $ourHistory['wysiwyg_description'] !!}
- +
diff --git a/resources/views/components/front/pages/known-us/our-governance.blade.php b/resources/views/components/front/pages/know-us/our-governance.blade.php similarity index 100% rename from resources/views/components/front/pages/known-us/our-governance.blade.php rename to resources/views/components/front/pages/know-us/our-governance.blade.php diff --git a/resources/views/components/front/pages/know-us/our-implantations.blade.php b/resources/views/components/front/pages/know-us/our-implantations.blade.php new file mode 100644 index 00000000..b0591a62 --- /dev/null +++ b/resources/views/components/front/pages/know-us/our-implantations.blade.php @@ -0,0 +1,280 @@ +
+
+ {{-- Title --}} + + {{-- Content --}} +
+ {!! $implantations['wysiwyg_content'] !!} +
+ {{-- Interactive Map --}} +
+ {{-- Legend --}} +
+

{{ trans('front.filter_plants') }}

+
+

{{ trans('front.pole') }}

+ @foreach ($companyActivityModels as $activity) + + @endforeach +
+ {{-- Company Info --}} +
+ +
+ +
+

+

+

{{ trans('front.responsible') }} :

+
+
+
+

{{ trans('front.address') }} :

+

+
+ {{-- Map --}} +
+
+
+ +
+
+
+ + + + \ No newline at end of file diff --git a/resources/views/components/front/pages/known-us/our-organisation.blade.php b/resources/views/components/front/pages/know-us/our-organisation.blade.php similarity index 100% rename from resources/views/components/front/pages/known-us/our-organisation.blade.php rename to resources/views/components/front/pages/know-us/our-organisation.blade.php diff --git a/resources/views/components/front/pages/known-us/pole-page-template.blade.php b/resources/views/components/front/pages/know-us/pole-page-template.blade.php similarity index 100% rename from resources/views/components/front/pages/known-us/pole-page-template.blade.php rename to resources/views/components/front/pages/know-us/pole-page-template.blade.php diff --git a/resources/views/components/front/pages/our-jobs/our-professions.blade.php b/resources/views/components/front/pages/our-jobs/our-professions.blade.php index ba1bf985..e1dd9c99 100644 --- a/resources/views/components/front/pages/our-jobs/our-professions.blade.php +++ b/resources/views/components/front/pages/our-jobs/our-professions.blade.php @@ -87,7 +87,8 @@ @if(!empty($professions))
- +
@foreach ($professions['list'] as $profession) diff --git a/resources/views/components/front/sections/title.blade.php b/resources/views/components/front/sections/title.blade.php index 5778c442..3af89ca8 100644 --- a/resources/views/components/front/sections/title.blade.php +++ b/resources/views/components/front/sections/title.blade.php @@ -1,4 +1,4 @@ -

+

{!! $title !!} @if (isset($subtitle)) {{ $subtitle }} diff --git a/resources/views/front/layouts/head.blade.php b/resources/views/front/layouts/head.blade.php index 5cdba94a..66e8365c 100644 --- a/resources/views/front/layouts/head.blade.php +++ b/resources/views/front/layouts/head.blade.php @@ -21,7 +21,7 @@ - @@ -59,7 +59,7 @@ @endphp @foreach ($scriptFiles as $scriptFile) - + @endforeach diff --git a/resources/views/front/layouts/header.blade.php b/resources/views/front/layouts/header.blade.php index 31b6e4e5..1aa85fc8 100644 --- a/resources/views/front/layouts/header.blade.php +++ b/resources/views/front/layouts/header.blade.php @@ -235,7 +235,7 @@

- + + + @endif @endsection diff --git a/routes/breadcrumbs-back.php b/routes/breadcrumbs-back.php index a6c621a9..ff6d1b29 100644 --- a/routes/breadcrumbs-back.php +++ b/routes/breadcrumbs-back.php @@ -157,3 +157,102 @@ Breadcrumbs::for('back.contact-counts.index', function (Generator $trail) { route('back.contact-counts.index') ); }); + +// * COMPANIES. +Breadcrumbs::for('back.companies.index', function (Generator $trail) { + $trail->parent('back.dashboard.index'); + $trail->push( + Str::of(trans_choice('models.classes.company', \INF))->ucfirst()->plural(), + route('back.companies.index'), + ); +}); +Breadcrumbs::for('back.companies.create', function (Generator $trail) { + $trail->parent('back.companies.index'); + $trail->push(Str::ucfirst(trans('crud.actions.create')), route('back.companies.create')); +}); +Breadcrumbs::for('back.companies.edit', function (Generator $trail) { + $trail->parent('back.companies.index'); + $trail->push(Str::ucfirst(trans('crud.actions.edit')), route('back.companies.edit', [ + 'company' => request()->company + ])); +}); +Breadcrumbs::for('back.companies.duplicate', function (Generator $trail) { + $trail->parent('back.companies.index'); + $trail->push(Str::ucfirst(trans('crud.actions.duplicate'))); +}); +Breadcrumbs::for('back.companies.show', function (Generator $trail) { + $trail->parent('back.companies.index'); + $trail->push(Str::ucfirst(trans('crud.actions.visualize')), route('back.companies.show', [ + 'company' => request()->company + ])); +}); +Breadcrumbs::for('back.companies.trash', function (Generator $trail) { + $trail->parent('back.companies.index'); + $trail->push(Str::ucfirst(trans('crud.actions.archive'))); +}); + +// * COMPANY SECTORS. +Breadcrumbs::for('back.company-sectors.index', function (Generator $trail) { + $trail->parent('back.dashboard.index'); + $trail->push( + Str::of(trans('models.classes.company'))->ucfirst()->plural(), + route('back.company-sectors.index'), + ); +}); +Breadcrumbs::for('back.company-sectors.create', function (Generator $trail) { + $trail->parent('back.company-sectors.index'); + $trail->push(Str::ucfirst(trans('crud.actions.create')), route('back.company-sectors.create')); +}); +Breadcrumbs::for('back.company-sectors.edit', function (Generator $trail) { + $trail->parent('back.company-sectors.index'); + $trail->push(Str::ucfirst(trans('crud.actions.edit')), route('back.company-sectors.edit', [ + 'company_sector' => request()->company_sector, + ])); +}); +Breadcrumbs::for('back.company-sectors.duplicate', function (Generator $trail) { + $trail->parent('back.company-sectors.index'); + $trail->push(Str::ucfirst(trans('crud.actions.duplicate'))); +}); +Breadcrumbs::for('back.company-sectors.show', function (Generator $trail) { + $trail->parent('back.company-sectors.index'); + $trail->push(Str::ucfirst(trans('crud.actions.visualize')), route('back.company-sectors.show', [ + 'company_sector' => request()->company_sector, + ])); +}); +Breadcrumbs::for('back.company-sectors.trash', function (Generator $trail) { + $trail->parent('back.company-sectors.index'); + $trail->push(Str::ucfirst(trans('crud.actions.archive'))); +}); + +// * COMPANY ACTIVITIES. +Breadcrumbs::for('back.company-activities.index', function (Generator $trail) { + $trail->parent('back.dashboard.index'); + $trail->push( + Str::of(trans('models.classes.company'))->ucfirst()->plural(), + route('back.company-activities.index'), + ); +}); +Breadcrumbs::for('back.company-activities.create', function (Generator $trail) { + $trail->parent('back.company-activities.index'); + $trail->push(Str::ucfirst(trans('crud.actions.create')), route('back.company-activities.create')); +}); +Breadcrumbs::for('back.company-activities.edit', function (Generator $trail) { + $trail->parent('back.company-activities.index'); + $trail->push(Str::ucfirst(trans('crud.actions.edit')), route('back.company-activities.edit', [ + 'company_activity' => request()->company_activity, + ])); +}); +Breadcrumbs::for('back.company-activities.duplicate', function (Generator $trail) { + $trail->parent('back.company-activities.index'); + $trail->push(Str::ucfirst(trans('crud.actions.duplicate'))); +}); +Breadcrumbs::for('back.company-activities.show', function (Generator $trail) { + $trail->parent('back.company-activities.index'); + $trail->push(Str::ucfirst(trans('crud.actions.visualize')), route('back.company-activities.show', [ + 'company_activity' => request()->company_activity, + ])); +}); +Breadcrumbs::for('back.company-activities.trash', function (Generator $trail) { + $trail->parent('back.company-activities.index'); + $trail->push(Str::ucfirst(trans('crud.actions.archive'))); +}); \ No newline at end of file diff --git a/routes/web-back.php b/routes/web-back.php index e5faa19a..5ee19e7d 100644 --- a/routes/web-back.php +++ b/routes/web-back.php @@ -1,12 +1,15 @@ name('news.duplicate'); + + // * COMPANIES. + Route::get('/companies/trash', [CompanyController::class, 'index']) + ->name('companies.trash'); + Route::patch('/companies/{company}/restore', [CompanyController::class, 'restore']) + ->name('companies.restore'); + Route::delete('/companies/{company}/force', [CompanyController::class, 'forceDestroy']) + ->name('companies.forceDestroy'); + Route::resource('companies', CompanyController::class); + Route::get('/companies/{company}/duplicate', [CompanyController::class, 'duplicate']) + ->name('companies.duplicate'); + + // * COMPANY SECTORS. + Route::get('/company-sectors/trash', [CompanySectorController::class, 'index']) + ->name('company-sectors.trash'); + Route::patch('/company-sectors/{company_sector}/restore', [CompanySectorController::class, 'restore']) + ->name('company-sectors.restore'); + Route::delete('/company-sectors/{company_sector}/force', [CompanySectorController::class, 'forceDestroy']) + ->name('company-sectors.forceDestroy'); + Route::resource('company-sectors', CompanySectorController::class); + Route::get('/company-sectors/{company_sector}/duplicate', [CompanySectorController::class, 'duplicate']) + ->name('company-sectors.duplicate'); + + // * COMPANY ACTIVITIES. + Route::get('/company-activities/trash', [CompanyActivityController::class, 'index']) + ->name('company-activities.trash'); + Route::patch('/company-activities/{company_activity}/restore', [CompanyActivityController::class, 'restore']) + ->name('company-activities.restore'); + Route::delete('/company-activities/{company_activity}/force', [CompanyActivityController::class, 'forceDestroy']) + ->name('company-activities.forceDestroy'); + Route::resource('company-activities', CompanyActivityController::class); + Route::get('/company-activities/{company_activity}/duplicate', [CompanyActivityController::class, 'duplicate']) + ->name('company-activities.duplicate'); }); // * UPDATE LANGUAGES.