feat: 🚨 resolve php errors

This commit is contained in:
Alexis Gousseau 2026-05-19 12:25:21 +02:00
parent cc45c363b5
commit 6e6f3d55b5
No known key found for this signature in database
GPG key ID: 7F3C786EE12DBB72
30 changed files with 264 additions and 238 deletions

View file

@ -106,17 +106,23 @@ class MakeUser extends Command
/**
* Ask for a role and return the corresponding RoleEnum.
*
* @return object
* @return object{name: string, value: int|string, label: string}
*/
private function askRole(): object
{
$options = collect(UserRoleRegistry::all())->mapWithKeys(fn(object $role) => [
Str::ucFirst($role->label) => $role
]);
$roles = UserRoleRegistry::all();
$defaultRole = UserRoleRegistry::get('client');
$choice = $this->choice('Role', $options->keys()->all(), Str::ucFirst(UserRoleRegistry::get('client')->label));
$options = collect($roles)->mapWithKeys(
fn(object $role) => [Str::ucFirst($role->label) => $role]);
$choice = $this->choice(
'Role',
$options->keys()->all(),
Str::ucFirst($defaultRole->label),
);
$choiceKey = is_string($choice) ? $choice : (string) $choice[0];
return $options->get($choiceKey) ?? UserRoleRegistry::get('client');
return $options->get($choiceKey) ?? $defaultRole;
}
/**

View file

@ -54,4 +54,3 @@ enum NoticeTypeEnum: int
return self::CLASSES;
}
}

View file

@ -48,11 +48,11 @@ class InvoiceCompanyController extends BackendController
$query,
$search,
null,
// TODO: Fields here.
'name',
);
}
$searchFields = \implode(', ', [
// TODO: Translations here.
trans('validation.attributes.name'),
]);
/** Sort columns with a query */
@ -104,7 +104,7 @@ class InvoiceCompanyController extends BackendController
{
return DB::transaction(function () use ($request) {
$invoice_company = new InvoiceCompany();
$invoice_company->inertiaFill($request->validated());
$invoice_company->fill($request->validated());
if ($invoice_company->saveOrFail()) {
return redirect()->route("back.$this->modelName.edit", $invoice_company)
@ -136,7 +136,7 @@ class InvoiceCompanyController extends BackendController
* Update the specified resource.
*
* @param \App\Http\Requests\Back\InvoiceCompanies\UpdateInvoiceCompanyRequest $request
* @param \App\Models\InvoiceCompany $invoice_company
* @param \App\Models\InvoiceCompany $invoice_company
* @return \Illuminate\Http\RedirectResponse
*/
public function update(
@ -144,7 +144,7 @@ class InvoiceCompanyController extends BackendController
InvoiceCompany $invoice_company
): \Illuminate\Http\RedirectResponse {
return DB::transaction(function () use ($request, $invoice_company) {
$invoice_company->inertiaFill($request->validated());
$invoice_company->fill($request->validated());
if ($invoice_company->saveOrFail()) {
return redirect()->route("back.$this->modelName.edit", $invoice_company)

View file

@ -48,11 +48,11 @@ class InvoicePackageController extends BackendController
$query,
$search,
null,
// TODO: Fields here.
'name',
);
}
$searchFields = \implode(', ', [
// TODO: Translations here.
trans('validation.attributes.name'),
]);
/** Sort columns with a query */
@ -104,7 +104,7 @@ class InvoicePackageController extends BackendController
{
return DB::transaction(function () use ($request) {
$invoice_package = new InvoicePackage();
$invoice_package->inertiaFill($request->validated());
$invoice_package->fill($request->validated());
if ($invoice_package->saveOrFail()) {
return redirect()->route("back.$this->modelName.edit", $invoice_package)
@ -136,7 +136,7 @@ class InvoicePackageController extends BackendController
* Update the specified resource.
*
* @param \App\Http\Requests\Back\InvoicePackages\UpdateInvoicePackageRequest $request
* @param \App\Models\InvoicePackage $invoice_package
* @param \App\Models\InvoicePackage $invoice_package
* @return \Illuminate\Http\RedirectResponse
*/
public function update(
@ -144,7 +144,7 @@ class InvoicePackageController extends BackendController
InvoicePackage $invoice_package
): \Illuminate\Http\RedirectResponse {
return DB::transaction(function () use ($request, $invoice_package) {
$invoice_package->inertiaFill($request->validated());
$invoice_package->fill($request->validated());
if ($invoice_package->saveOrFail()) {
return redirect()->route("back.$this->modelName.edit", $invoice_package)

View file

@ -48,11 +48,11 @@ class NoticeController extends BackendController
$query,
$search,
null,
// TODO: Fields here.
'title',
);
}
$searchFields = \implode(', ', [
// TODO: Translations here.
trans('validation.attributes.title'),
]);
/** Sort columns with a query */
@ -104,7 +104,7 @@ class NoticeController extends BackendController
{
return DB::transaction(function () use ($request) {
$notice = new Notice();
$notice->inertiaFill($request->validated());
$notice->fill($request->validated());
if ($notice->saveOrFail()) {
return redirect()->route("back.$this->modelName.edit", $notice)
@ -136,7 +136,7 @@ class NoticeController extends BackendController
* Update the specified resource.
*
* @param \App\Http\Requests\Back\Notices\UpdateNoticeRequest $request
* @param \App\Models\Notice $notice
* @param \App\Models\Notice $notice
* @return \Illuminate\Http\RedirectResponse
*/
public function update(
@ -144,7 +144,7 @@ class NoticeController extends BackendController
Notice $notice
): \Illuminate\Http\RedirectResponse {
return DB::transaction(function () use ($request, $notice) {
$notice->inertiaFill($request->validated());
$notice->fill($request->validated());
if ($notice->saveOrFail()) {
return redirect()->route("back.$this->modelName.edit", $notice)

View file

@ -32,7 +32,7 @@ class StoreNoticeRequest extends FormRequest
public function rules(): array
{
return [
'title' => 'required|string|min:3|max:255',
'title' => 'required|string|between:3,255',
'message' => ['required', 'string', new WysiwygLength()],
'type' => ['required', 'integer', new Enum(NoticeTypeEnum::class)],
];

View file

@ -10,15 +10,20 @@ class LinkResetPasswordMail extends Mailable
{
/**
* Create a new message instance.
*
* @param string $url
* @param mixed $user
* @return void
*/
public function __construct(
public string $url,
public mixed $user,
) {}
) {
}
/**
* Get the message envelope.
*
*
* @return \Illuminate\Mail\Mailables\Envelope
*/
public function envelope(): \Illuminate\Mail\Mailables\Envelope
@ -35,7 +40,7 @@ class LinkResetPasswordMail extends Mailable
/**
* Get the message content definition.
*
*
* @return \Illuminate\Mail\Mailables\Content
*/
public function content(): \Illuminate\Mail\Mailables\Content

View file

@ -57,4 +57,4 @@ class ResetPassword extends Mailable
],
);
}
}
}

View file

@ -8,7 +8,6 @@ use Illuminate\Database\Eloquent\SoftDeletes;
use Uwil\LaravelActivityLogs\Traits\HasActivityLog;
use Uwil\LaravelBackend\Traits\Models\HasCache;
use Uwil\LaravelBackend\Traits\Models\HasModelNaming;
use Uwil\LaravelBackend\Traits\Models\HasUwilImages;
use Uwil\LaravelI18n\Traits\Models\HasTranslations;
/**
@ -22,10 +21,10 @@ class InvoiceCompany extends Model
{
use HasActivityLog;
use HasCache;
/** @use \Illuminate\Database\Eloquent\Factories\HasFactory<\Database\Factories\InvoiceCompanyFactory> */
use HasFactory;
use HasModelNaming;
use HasTranslations;
use HasUwilImages;
use SoftDeletes;
/**

View file

@ -8,7 +8,6 @@ use Illuminate\Database\Eloquent\SoftDeletes;
use Uwil\LaravelActivityLogs\Traits\HasActivityLog;
use Uwil\LaravelBackend\Traits\Models\HasCache;
use Uwil\LaravelBackend\Traits\Models\HasModelNaming;
use Uwil\LaravelBackend\Traits\Models\HasUwilImages;
use Uwil\LaravelI18n\Traits\Models\HasTranslations;
/**
@ -24,10 +23,10 @@ class InvoicePackage extends Model
{
use HasActivityLog;
use HasCache;
/** @use \Illuminate\Database\Eloquent\Factories\HasFactory<\Database\Factories\InvoicePackageFactory> */
use HasFactory;
use HasModelNaming;
use HasTranslations;
use HasUwilImages;
use SoftDeletes;
/**

View file

@ -9,7 +9,6 @@ use Illuminate\Database\Eloquent\SoftDeletes;
use Uwil\LaravelActivityLogs\Traits\HasActivityLog;
use Uwil\LaravelBackend\Traits\Models\HasCache;
use Uwil\LaravelBackend\Traits\Models\HasModelNaming;
use Uwil\LaravelBackend\Traits\Models\HasUwilImages;
use Uwil\LaravelI18n\Traits\Models\HasTranslations;
/**
@ -25,10 +24,10 @@ class Notice extends Model
{
use HasActivityLog;
use HasCache;
/** @use \Illuminate\Database\Eloquent\Factories\HasFactory<\Database\Factories\NoticeFactory> */
use HasFactory;
use HasModelNaming;
use HasTranslations;
use HasUwilImages;
use SoftDeletes;
/**

View file

@ -43,7 +43,7 @@ class User extends BackendUser
url(route('back.reset-password', ['token' => $token], false)),
urlencode($this->getEmailForPasswordReset())
);
Mail::send(new LinkResetPasswordMail($url, $this));
}
@ -52,10 +52,10 @@ class User extends BackendUser
/**
* Get the user's associated password.
*
* @return \Illuminate\Database\Eloquent\Relations\HasOne<\App\Models\UserPassword>
* @return \Illuminate\Database\Eloquent\Relations\HasOne<\App\Models\UserPassword,\App\Models\User>
*/
public function userPassword(): \Illuminate\Database\Eloquent\Relations\HasOne
{
return $this->hasOne(UserPassword::class);
}
}
}

View file

@ -5,8 +5,9 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model;
/**
* @property \App\Models\User $user_id User associated.
* @property string $password User password.
* @property integer $id Id of the user password.
* @property \App\Models\User $user_id Associated user.
* @property string $password Password of the user.
* @property-read \Illuminate\Support\Carbon $created_at Date on which the password was created.
* @property-read \Illuminate\Support\Carbon $updated_at Date on which the password was updated.
*/
@ -22,4 +23,4 @@ class UserPassword extends Model
'user_id',
'password',
];
}
}

View file

@ -19,4 +19,4 @@ class AppServiceProvider extends ServiceProvider
UserRoleRegistry::add(4, 'developper', trans('enums.user-role.developper'));
UserRoleRegistry::add(5, 'client', trans('enums.user-role.client'));
}
}
}

View file

@ -25,7 +25,7 @@ class InvoiceCompanyFactory extends Factory
public function definition(): array
{
return [
"name" => fake()->word(),
"name" => fake()->words(3, true),
];
}
}

View file

@ -25,7 +25,7 @@ class InvoicePackageFactory extends Factory
public function definition(): array
{
return [
"name" => fake()->word(),
"name" => fake()->words(3, true),
"amount" => fake()->randomFloat(2, 1, 1000),
"published" => fake()->boolean(75),
];

View file

@ -26,7 +26,7 @@ class NoticeFactory extends Factory
public function definition(): array
{
return [
"title" => fake()->word(),
"title" => fake()->words(3, true),
"message" => sprintf("<p>%s</p>", fake()->text(\rand(20, 40))),
"type" => fake()->randomElement(NoticeTypeEnum::cases()),
];

View file

@ -14,9 +14,9 @@ return new class extends Migration
public function up(): void
{
Schema::create('user_password_reset_tokens', function (Blueprint $table): void {
$table->string('email')->primary();
$table->string('token');
$table->timestamp('created_at')->nullable();
$table->string('email')->primary()->comment('Email of the user.');
$table->string('token')->comment('Token of the password reset.');
$table->timestamp('created_at')->nullable()->comment('Date the reset password was created.');
});
}

View file

@ -3,25 +3,25 @@
declare(strict_types=1);
return [
'failed' => 'Ces identifiants ne correspondent pas à nos enregistrements.',
'password' => 'Le mot de passe fourni est incorrect.',
'throttle' => 'Tentatives de connexion trop nombreuses. Veuillez réessayer dans :seconds secondes.',
"login" => "Se connecter",
"remember" => "Se souvenir de moi",
"forgot_password" => "Mot de passe oublié",
"forgot_password_desc" => "Renseignez votre email pour recevoir un lien de réinitialisation.",
"description" => "Connectez-vous afin d'accéder à notre outil <strong>:appName</strong> !",
"connected" => "Connecté !",
"connected_desc" => "Vous êtes à présent authentifié au Support UWIL.",
"send_link" => "Envoyer le lien",
"mail_sent" => "Mail envoyé !",
"mail_sent_desc" => "Si un compte est associé à l'adresse :email, un e-mail de réinitialisation du mot de passe
'failed' => 'Ces identifiants ne correspondent pas à nos enregistrements.',
'password' => 'Le mot de passe fourni est incorrect.',
'throttle' => 'Tentatives de connexion trop nombreuses. Veuillez réessayer dans :seconds secondes.',
"login" => "Se connecter",
"remember" => "Se souvenir de moi",
"forgot_password" => "Mot de passe oublié",
"forgot_password_desc" => "Renseignez votre email pour recevoir un lien de réinitialisation.",
"description" => "Connectez-vous afin d'accéder à notre outil <strong>:appName</strong> !",
"connected" => "Connecté !",
"connected_desc" => "Vous êtes à présent authentifié au Support UWIL.",
"send_link" => "Envoyer le lien",
"mail_sent" => "Mail envoyé !",
"mail_sent_desc" => "Si un compte est associé à l'adresse :email, un e-mail de réinitialisation du mot de passe
vous sera envoyé dans quelques instants.",
"reset_password" => "Réinitialisation du mot de passe",
"reset_password_desc" => "Choisissez un nouveau mot de passe pour votre compte.",
"reset_your_password" => "Réinitialiser votre mot de passe",
"reset_sent" => "Réinitialisation du mot de passe effectué !",
"reset_sent_desc" => "Mot de passe mis à jour avec succès. Vous pouvez dès à présent vous connecter
"reset_password" => "Réinitialisation du mot de passe",
"reset_password_desc" => "Choisissez un nouveau mot de passe pour votre compte.",
"reset_your_password" => "Réinitialiser votre mot de passe",
"reset_sent" => "Réinitialisation du mot de passe effectué !",
"reset_sent_desc" => "Mot de passe mis à jour avec succès. Vous pouvez dès à présent vous connecter
avec vos nouveaux identifiants.",
'email_hello' => 'Bonjour !',
'email_get_reset_password' => 'Vous recevez cet e-mail parce que nous avons reçu une demande de réinitialisation

View file

@ -982,7 +982,7 @@ export const MultiSelect = forwardRef<MultiSelectRef, MultiSelectProps>(
}, [minSelection, maxSelection, multiple]);
return (
<div className="w-full flex flex-col w-full justify-start items-start gap-1.5">
<div className="w-full flex flex-col justify-start items-start gap-1.5">
<div className="sr-only">
<div aria-live="polite" aria-atomic="true" role="status">
{politeMessage}
@ -1054,143 +1054,159 @@ export const MultiSelect = forwardRef<MultiSelectRef, MultiSelectProps>(
responsiveSettings.compactMode && "gap-0.5",
)}
>
{selectedValues
.slice(0, responsiveSettings.maxCount)
.map((value) => {
const option = getOptionByValue(value);
const IconComponent = option?.icon;
const customStyle = option?.style;
if (!option) {
return null;
}
const badgeStyle: CSSProperties = {
animationDuration: `${animation}s`,
...(customStyle?.badgeColor && {
backgroundColor: customStyle.badgeColor,
}),
...(customStyle?.gradient && {
background: customStyle.gradient,
color: "white",
}),
};
return (
<Badge
key={value}
className={cn(
getBadgeAnimationClass(),
multiSelectVariants({ variant }),
customStyle?.gradient &&
"text-white border-transparent",
responsiveSettings.compactMode &&
"text-xs px-1.5 py-0.5",
screenSize === "mobile" &&
"max-w-[120px] truncate",
singleLine && "flex-shrink-0 whitespace-nowrap",
"[&>svg]:pointer-events-auto",
)}
style={{
...badgeStyle,
animationDuration: `${
animationConfig?.duration || animation
}s`,
animationDelay: `${animationConfig?.delay || 0}s`,
}}
>
{IconComponent && !responsiveSettings.hideIcons && (
<IconComponent
{multiple
? selectedValues
.slice(0, responsiveSettings.maxCount)
.map((value) => {
const option = getOptionByValue(value);
const IconComponent = option?.icon;
const customStyle = option?.style;
if (!option) {
return null;
}
const badgeStyle: CSSProperties = {
animationDuration: `${animation}s`,
...(customStyle?.badgeColor && {
backgroundColor: customStyle.badgeColor,
}),
...(customStyle?.gradient && {
background: customStyle.gradient,
color: "white",
}),
};
return (
<Badge
key={value}
className={cn(
"h-4 w-4 mr-2",
getBadgeAnimationClass(),
multiSelectVariants({ variant }),
customStyle?.gradient &&
"text-white border-transparent",
responsiveSettings.compactMode &&
"h-3 w-3 mr-1",
customStyle?.iconColor && "text-current",
"text-xs px-1.5 py-0.5",
screenSize === "mobile" &&
"max-w-[120px] truncate",
singleLine &&
"flex-shrink-0 whitespace-nowrap",
"[&>svg]:pointer-events-auto",
)}
// eslint-disable-next-line react/jsx-props-no-spreading
{...(customStyle?.iconColor && {
style: {
color: customStyle.iconColor,
},
})}
/>
)}
<span
className={cn(
screenSize === "mobile" && "truncate",
)}
>
{option.label}
</span>
<div
role="button"
tabIndex={0}
onClick={(event) => {
event.stopPropagation();
toggleOption(value);
}}
onKeyDown={(event) => {
if (
event.key === "Enter" ||
event.key === " "
) {
event.preventDefault();
event.stopPropagation();
toggleOption(value);
}
}}
aria-label={`Remove ${option.label} from selection`}
className="ml-2 h-4 w-4 cursor-pointer hover:bg-white/20 rounded-sm -m-0.5 focus:outline-none focus:ring-1 focus:ring-white/50"
>
<XCircleIcon
className={cn(
"h-3 w-3",
responsiveSettings.compactMode &&
"h-2.5 w-2.5",
)}
/>
</div>
</Badge>
);
})
.filter(Boolean)}
{selectedValues.length > responsiveSettings.maxCount && (
<Badge
className={cn(
"bg-transparent text-foreground border-foreground/1 hover:bg-transparent",
getBadgeAnimationClass(),
multiSelectVariants({
variant,
}),
responsiveSettings.compactMode &&
"text-xs px-1.5 py-0.5",
singleLine && "flex-shrink-0 whitespace-nowrap",
"[&>svg]:pointer-events-auto",
)}
style={{
animationDuration: `${animationConfig?.duration || animation}s`,
animationDelay: `${animationConfig?.delay || 0}s`,
}}
>
{`+ ${
selectedValues.length - responsiveSettings.maxCount
} ${transMore}`}
<XCircleIcon
style={{
...badgeStyle,
animationDuration: `${
animationConfig?.duration || animation
}s`,
animationDelay: `${animationConfig?.delay || 0}s`,
}}
>
{IconComponent &&
!responsiveSettings.hideIcons && (
<IconComponent
className={cn(
"h-4 w-4 mr-2",
responsiveSettings.compactMode &&
"h-3 w-3 mr-1",
customStyle?.iconColor &&
"text-current",
)}
// eslint-disable-next-line react/jsx-props-no-spreading
{...(customStyle?.iconColor && {
style: {
color: customStyle.iconColor,
},
})}
/>
)}
<span
className={cn(
screenSize === "mobile" && "truncate",
)}
>
{option.label}
</span>
<div
role="button"
tabIndex={0}
onClick={(event) => {
event.stopPropagation();
toggleOption(value);
}}
onKeyDown={(event) => {
if (
event.key === "Enter" ||
event.key === " "
) {
event.preventDefault();
event.stopPropagation();
toggleOption(value);
}
}}
aria-label={`Remove ${option.label} from selection`}
className="ml-2 h-4 w-4 cursor-pointer hover:bg-white/20 rounded-sm -m-0.5 focus:outline-none focus:ring-1 focus:ring-white/50"
>
<XCircleIcon
className={cn(
"h-3 w-3",
responsiveSettings.compactMode &&
"h-2.5 w-2.5",
)}
/>
</div>
</Badge>
);
})
.filter(Boolean)
: selectedValues
.slice(0, responsiveSettings.maxCount)
.map((value) => {
const option = getOptionByValue(value);
if (!option) {
return null;
}
return <span>{option.label}</span>;
})}
{multiple &&
selectedValues.length > responsiveSettings.maxCount && (
<Badge
className={cn(
"ml-2 h-4 w-4 cursor-pointer",
responsiveSettings.compactMode && "ml-1 h-3 w-3",
"bg-transparent text-foreground border-foreground/1 hover:bg-transparent",
getBadgeAnimationClass(),
multiSelectVariants({
variant,
}),
responsiveSettings.compactMode &&
"text-xs px-1.5 py-0.5",
singleLine && "flex-shrink-0 whitespace-nowrap",
"[&>svg]:pointer-events-auto",
)}
onClick={(event) => {
event.stopPropagation();
clearExtraOptions();
style={{
animationDuration: `${animationConfig?.duration || animation}s`,
animationDelay: `${animationConfig?.delay || 0}s`,
}}
/>
</Badge>
)}
>
{`+ ${
selectedValues.length - responsiveSettings.maxCount
} ${transMore}`}
<XCircleIcon
className={cn(
"ml-2 h-4 w-4 cursor-pointer",
responsiveSettings.compactMode && "ml-1 h-3 w-3",
)}
onClick={(event) => {
event.stopPropagation();
clearExtraOptions();
}}
/>
</Badge>
)}
</div>
<div className="flex items-center justify-between">
<Button
type="button"
role="button"
variant="ghost"
tabIndex={0}
onClick={(event) => {
event.preventDefault();
event.stopPropagation();
handleClear();
}}
@ -1218,7 +1234,7 @@ export const MultiSelect = forwardRef<MultiSelectRef, MultiSelectProps>(
</div>
) : (
<div className="flex items-center justify-between w-full mx-auto gap-2">
<p className="text-start text-sm whitespace-pre-line">
<p className="text-start text-sm text-muted-foreground whitespace-pre-line">
{placeholder}
</p>
<ChevronsUpDownIcon className="h-4 cursor-pointer opacity-50 group-hover/button:opacity-60" />

View file

@ -5,7 +5,6 @@ import {
ChevronDownIcon,
MoreHorizontalIcon,
HomeIcon,
SquareArrowOutUpRightIcon,
TelescopeIcon,
} from "lucide-react";
import { route } from "ziggy-js";
@ -134,7 +133,6 @@ export default function AppSidebar() {
// Translations.
const transPages = useTrans("uwil-backend::back.pages");
const transDashboard = useTrans("uwil-backend::back.dashboard");
const transWebsite = useTrans("uwil-backend::back.your_website");
const transModules = useTrans("uwil-backend::back.modules");
const transAdmin = useTrans("uwil-backend::enums.user-role.admin");
const transTelescope = useTrans("uwil-backend::back.telescope");
@ -150,12 +148,6 @@ export default function AppSidebar() {
show: true,
icon: HomeIcon,
},
{
title: transWebsite,
link: "/",
show: true,
icon: SquareArrowOutUpRightIcon,
},
...SidebarRegistry.getAll(auth, "pages"),
],
},

View file

@ -16,20 +16,17 @@ type DefaultModel = {
id: number;
created_at: Date;
updated_at: Date;
deleted_at: Date;
};
// User type, with policies.
type UserModel = {
policies: ModelPolicy;
id: number;
type UserModel = DefaultModel & {
first_name: string;
last_name: string;
email: string;
role: { value: number; label: string; name: string };
published: boolean;
published_at: Date;
created_at: Date;
updated_at: Date;
};
// Pagination-related types.

View file

@ -75,7 +75,7 @@ const useTrans = (key: string, options: UseTransOptions = {}): string => {
const parts = keyword.split("|");
if (parts.length !== 2) {
throw new Error(
"The input string must contain exactly one '|' character.",
`The input string '${keyword}' must contain exactly one '|' character.`,
);
}
keyword = choice === 1 ? parts[0].trim() : parts[1].trim();

View file

@ -1,11 +1,11 @@
// * Other
import { Model } from "@/back/types/global";
import { DefaultModel } from "@/back/types/global";
/**
* Extract ids from model relation pivot and format options
* for a multi select component.
*/
export function mapPivotOptions<T extends Model, D extends Model>(
export function mapPivotOptions<T extends DefaultModel, D extends DefaultModel>(
model: T[],
data?: D[],
valueKey?: keyof T,
@ -32,7 +32,7 @@ export function mapPivotOptions<T extends Model, D extends Model>(
return { options, defaultValue };
}
export function extractIdsFromDatabasePivotRelation<D extends Model>(
export function extractIdsFromDatabasePivotRelation<D extends DefaultModel>(
data?: D[],
): number[] {
return data ? data.map((item) => item.id) : [];

View file

@ -12,12 +12,12 @@ Route::prefix(config('uwil-backend.routes.prefix'))
->name('login');
Route::post('login', [AuthenticatedSessionController::class, 'postLogin'])
->name('login.post');
Route::get('forgot-password', [AuthenticatedSessionController::class, 'forgotPassword'])
->name('forgot-password');
Route::post('forgot-password', [AuthenticatedSessionController::class, 'postForgotPassword'])
->name('forgot-password.post');
Route::get('reset-password/{token}', [AuthenticatedSessionController::class, 'resetPassword'])
->name('reset-password');
Route::post('reset-password', [AuthenticatedSessionController::class, 'postResetPassword'])

View file

@ -1,4 +0,0 @@
<?php
// Set specific back routes here.
// ex: Route::resource('stories', OriginalStoryController::class);.

View file

@ -1 +0,0 @@
<?php

View file

@ -13,15 +13,18 @@ Breadcrumbs::for('back.invoice-companies.index', function (Generator $trail) {
Breadcrumbs::for('back.invoice-companies.create', function (Generator $trail) {
$trail->parent('back.invoice-companies.index');
$trail->push(
Str::ucfirst(trans_choice('models.classes.invoice-companies', 1)),
route('back.invoice-companies.create')
Str::ucfirst(trans('uwil-backend::crud.actions.create')),
route('back.invoice-companies.create'),
);
});
Breadcrumbs::for('back.invoice-companies.edit', function (Generator $trail) {
$trail->parent('back.invoice-companies.index');
$trail->push(Str::ucfirst(trans('uwil-backend::crud.actions.edit')), route('back.invoice-companies.edit', [
'invoice_company' => request()->invoice_company
]));
$trail->push(
Str::ucfirst(trans('uwil-backend::crud.actions.edit')),
route('back.invoice-companies.edit', [
'invoice_company' => request()->invoice_company,
]),
);
});
Breadcrumbs::for('back.invoice-companies.duplicate', function (Generator $trail) {
$trail->parent('back.invoice-companies.index');
@ -29,9 +32,12 @@ Breadcrumbs::for('back.invoice-companies.duplicate', function (Generator $trail)
});
Breadcrumbs::for('back.invoice-companies.show', function (Generator $trail) {
$trail->parent('back.invoice-companies.index');
$trail->push(Str::ucfirst(trans('uwil-backend::crud.actions.visualize')), route('back.invoice-companies.show', [
'invoice_company' => request()->invoice_company
]));
$trail->push(
Str::ucfirst(trans('uwil-backend::crud.actions.visualize')),
route('back.invoice-companies.show', [
'invoice_company' => request()->invoice_company,
]),
);
});
Breadcrumbs::for('back.invoice-companies.trash', function (Generator $trail) {
$trail->parent('back.invoice-companies.index');

View file

@ -13,15 +13,18 @@ Breadcrumbs::for('back.invoice-packages.index', function (Generator $trail) {
Breadcrumbs::for('back.invoice-packages.create', function (Generator $trail) {
$trail->parent('back.invoice-packages.index');
$trail->push(
Str::ucfirst(trans_choice('models.classes.invoice-packages', 1)),
route('back.invoice-packages.create')
Str::ucfirst(trans('uwil-backend::crud.actions.create')),
route('back.invoice-packages.create'),
);
});
Breadcrumbs::for('back.invoice-packages.edit', function (Generator $trail) {
$trail->parent('back.invoice-packages.index');
$trail->push(Str::ucfirst(trans('uwil-backend::crud.actions.edit')), route('back.invoice-packages.edit', [
'invoice_package' => request()->invoice_package
]));
$trail->push(
Str::ucfirst(trans('uwil-backend::crud.actions.edit')),
route('back.invoice-packages.edit', [
'invoice_package' => request()->invoice_package,
]),
);
});
Breadcrumbs::for('back.invoice-packages.duplicate', function (Generator $trail) {
$trail->parent('back.invoice-packages.index');
@ -29,9 +32,12 @@ Breadcrumbs::for('back.invoice-packages.duplicate', function (Generator $trail)
});
Breadcrumbs::for('back.invoice-packages.show', function (Generator $trail) {
$trail->parent('back.invoice-packages.index');
$trail->push(Str::ucfirst(trans('uwil-backend::crud.actions.visualize')), route('back.invoice-packages.show', [
'invoice_package' => request()->invoice_package
]));
$trail->push(
Str::ucfirst(trans('uwil-backend::crud.actions.visualize')),
route('back.invoice-packages.show', [
'invoice_package' => request()->invoice_package,
])
);
});
Breadcrumbs::for('back.invoice-packages.trash', function (Generator $trail) {
$trail->parent('back.invoice-packages.index');

View file

@ -13,15 +13,18 @@ Breadcrumbs::for('back.notices.index', function (Generator $trail) {
Breadcrumbs::for('back.notices.create', function (Generator $trail) {
$trail->parent('back.notices.index');
$trail->push(
Str::ucfirst(trans_choice('models.classes.notices', 1)),
route('back.notices.create')
Str::ucfirst(trans('uwil-backend::crud.actions.create')),
route('back.notices.create'),
);
});
Breadcrumbs::for('back.notices.edit', function (Generator $trail) {
$trail->parent('back.notices.index');
$trail->push(Str::ucfirst(trans('uwil-backend::crud.actions.edit')), route('back.notices.edit', [
'notice' => request()->notice
]));
$trail->push(
Str::ucfirst(trans('uwil-backend::crud.actions.edit')),
route('back.notices.edit', [
'notice' => request()->notice,
]),
);
});
Breadcrumbs::for('back.notices.duplicate', function (Generator $trail) {
$trail->parent('back.notices.index');
@ -29,9 +32,12 @@ Breadcrumbs::for('back.notices.duplicate', function (Generator $trail) {
});
Breadcrumbs::for('back.notices.show', function (Generator $trail) {
$trail->parent('back.notices.index');
$trail->push(Str::ucfirst(trans('uwil-backend::crud.actions.visualize')), route('back.notices.show', [
'notice' => request()->notice
]));
$trail->push(
Str::ucfirst(trans('uwil-backend::crud.actions.visualize')),
route('back.notices.show', [
'notice' => request()->notice,
]),
);
});
Breadcrumbs::for('back.notices.trash', function (Generator $trail) {
$trail->parent('back.notices.index');