base commit
This commit is contained in:
24
app/DTOs/EmployeeSummaryDto.php
Normal file
24
app/DTOs/EmployeeSummaryDto.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\DTOs;
|
||||
|
||||
use App\Models\Vacation;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
readonly class EmployeeSummaryDto
|
||||
{
|
||||
/**
|
||||
* @param Collection<int, Vacation> $upcomingLeave
|
||||
*/
|
||||
public function __construct(
|
||||
public int $vacationTaken,
|
||||
public int $vacationRemaining,
|
||||
public int $sickLeaveCount,
|
||||
public int $reportsCount,
|
||||
public float $bonusesTotal,
|
||||
public int $giftsCount,
|
||||
public Collection $upcomingLeave,
|
||||
) {}
|
||||
}
|
||||
39
app/DTOs/Import/BonusRowDto.php
Normal file
39
app/DTOs/Import/BonusRowDto.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\DTOs\Import;
|
||||
|
||||
readonly class BonusRowDto
|
||||
{
|
||||
public function __construct(
|
||||
public string $employeeNumber,
|
||||
public ?string $bonusDate,
|
||||
public ?string $bonusType,
|
||||
public ?float $amount,
|
||||
public ?string $reason,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $row
|
||||
*/
|
||||
public static function fromMappedRow(array $row): self
|
||||
{
|
||||
return new self(
|
||||
employeeNumber: (string) ($row['employee_number'] ?? ''),
|
||||
bonusDate: self::nullableString($row['bonus_date'] ?? null),
|
||||
bonusType: self::nullableString($row['bonus_type'] ?? null),
|
||||
amount: isset($row['amount']) && $row['amount'] !== '' ? (float) $row['amount'] : null,
|
||||
reason: self::nullableString($row['reason'] ?? null),
|
||||
);
|
||||
}
|
||||
|
||||
private static function nullableString(mixed $value): ?string
|
||||
{
|
||||
if ($value === null || $value === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (string) $value;
|
||||
}
|
||||
}
|
||||
55
app/DTOs/Import/EmployeeRowDto.php
Normal file
55
app/DTOs/Import/EmployeeRowDto.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\DTOs\Import;
|
||||
|
||||
readonly class EmployeeRowDto
|
||||
{
|
||||
public function __construct(
|
||||
public string $employeeNumber,
|
||||
public string $fullName,
|
||||
public ?string $nationalId,
|
||||
public ?string $gender,
|
||||
public ?string $birthDate,
|
||||
public ?string $phone,
|
||||
public ?string $address,
|
||||
public ?string $department,
|
||||
public ?string $position,
|
||||
public ?string $shift,
|
||||
public ?string $employmentStatus,
|
||||
public ?string $hireDate,
|
||||
public ?string $notes,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $row
|
||||
*/
|
||||
public static function fromMappedRow(array $row): self
|
||||
{
|
||||
return new self(
|
||||
employeeNumber: (string) ($row['employee_number'] ?? ''),
|
||||
fullName: (string) ($row['full_name'] ?? ''),
|
||||
nationalId: self::nullableString($row['national_id'] ?? null),
|
||||
gender: self::nullableString($row['gender'] ?? null),
|
||||
birthDate: self::nullableString($row['birth_date'] ?? null),
|
||||
phone: self::nullableString($row['phone'] ?? null),
|
||||
address: self::nullableString($row['address'] ?? null),
|
||||
department: self::nullableString($row['department'] ?? null),
|
||||
position: self::nullableString($row['position'] ?? null),
|
||||
shift: self::nullableString($row['shift'] ?? null),
|
||||
employmentStatus: self::nullableString($row['employment_status'] ?? null),
|
||||
hireDate: self::nullableString($row['hire_date'] ?? null),
|
||||
notes: self::nullableString($row['notes'] ?? null),
|
||||
);
|
||||
}
|
||||
|
||||
private static function nullableString(mixed $value): ?string
|
||||
{
|
||||
if ($value === null || $value === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (string) $value;
|
||||
}
|
||||
}
|
||||
33
app/DTOs/Import/ImportResultDto.php
Normal file
33
app/DTOs/Import/ImportResultDto.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\DTOs\Import;
|
||||
|
||||
readonly class ImportResultDto
|
||||
{
|
||||
/**
|
||||
* @param array<int, string> $errors
|
||||
*/
|
||||
public function __construct(
|
||||
public int $total,
|
||||
public int $imported,
|
||||
public int $skipped,
|
||||
public int $failed,
|
||||
public array $errors = [],
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'total' => $this->total,
|
||||
'imported' => $this->imported,
|
||||
'skipped' => $this->skipped,
|
||||
'failed' => $this->failed,
|
||||
'errors' => $this->errors,
|
||||
];
|
||||
}
|
||||
}
|
||||
39
app/DTOs/Import/ReportRowDto.php
Normal file
39
app/DTOs/Import/ReportRowDto.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\DTOs\Import;
|
||||
|
||||
readonly class ReportRowDto
|
||||
{
|
||||
public function __construct(
|
||||
public string $employeeNumber,
|
||||
public ?string $reportDate,
|
||||
public ?string $title,
|
||||
public ?string $description,
|
||||
public ?string $severity,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $row
|
||||
*/
|
||||
public static function fromMappedRow(array $row): self
|
||||
{
|
||||
return new self(
|
||||
employeeNumber: (string) ($row['employee_number'] ?? ''),
|
||||
reportDate: self::nullableString($row['report_date'] ?? null),
|
||||
title: self::nullableString($row['title'] ?? null),
|
||||
description: self::nullableString($row['description'] ?? null),
|
||||
severity: self::nullableString($row['severity'] ?? null),
|
||||
);
|
||||
}
|
||||
|
||||
private static function nullableString(mixed $value): ?string
|
||||
{
|
||||
if ($value === null || $value === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (string) $value;
|
||||
}
|
||||
}
|
||||
45
app/DTOs/Import/VacationRowDto.php
Normal file
45
app/DTOs/Import/VacationRowDto.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\DTOs\Import;
|
||||
|
||||
readonly class VacationRowDto
|
||||
{
|
||||
public function __construct(
|
||||
public string $employeeNumber,
|
||||
public ?string $type,
|
||||
public ?string $startDate,
|
||||
public ?string $endDate,
|
||||
public ?string $returnDate,
|
||||
public ?int $days,
|
||||
public ?string $status,
|
||||
public ?string $reason,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $row
|
||||
*/
|
||||
public static function fromMappedRow(array $row): self
|
||||
{
|
||||
return new self(
|
||||
employeeNumber: (string) ($row['employee_number'] ?? ''),
|
||||
type: self::nullableString($row['type'] ?? null),
|
||||
startDate: self::nullableString($row['start_date'] ?? null),
|
||||
endDate: self::nullableString($row['end_date'] ?? null),
|
||||
returnDate: self::nullableString($row['return_date'] ?? null),
|
||||
days: isset($row['days']) && $row['days'] !== '' ? (int) $row['days'] : null,
|
||||
status: self::nullableString($row['status'] ?? null),
|
||||
reason: self::nullableString($row['reason'] ?? null),
|
||||
);
|
||||
}
|
||||
|
||||
private static function nullableString(mixed $value): ?string
|
||||
{
|
||||
if ($value === null || $value === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (string) $value;
|
||||
}
|
||||
}
|
||||
39
app/Enums/ApprovalStatus.php
Normal file
39
app/Enums/ApprovalStatus.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum ApprovalStatus: string
|
||||
{
|
||||
case Pending = 'pending';
|
||||
case Approved = 'approved';
|
||||
case Rejected = 'rejected';
|
||||
|
||||
public function label(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Pending => 'Pending',
|
||||
self::Approved => 'Approved',
|
||||
self::Rejected => 'Rejected',
|
||||
};
|
||||
}
|
||||
|
||||
public function color(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Pending => 'warning',
|
||||
self::Approved => 'success',
|
||||
self::Rejected => 'danger',
|
||||
};
|
||||
}
|
||||
|
||||
public function icon(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Pending => 'heroicon-o-clock',
|
||||
self::Approved => 'heroicon-o-check-badge',
|
||||
self::Rejected => 'heroicon-o-x-mark',
|
||||
};
|
||||
}
|
||||
}
|
||||
43
app/Enums/BonusType.php
Normal file
43
app/Enums/BonusType.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum BonusType: string
|
||||
{
|
||||
case Performance = 'performance';
|
||||
case Holiday = 'holiday';
|
||||
case Retention = 'retention';
|
||||
case Other = 'other';
|
||||
|
||||
public function label(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Performance => 'Performance',
|
||||
self::Holiday => 'Holiday',
|
||||
self::Retention => 'Retention',
|
||||
self::Other => 'Other',
|
||||
};
|
||||
}
|
||||
|
||||
public function color(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Performance => 'success',
|
||||
self::Holiday => 'primary',
|
||||
self::Retention => 'info',
|
||||
self::Other => 'gray',
|
||||
};
|
||||
}
|
||||
|
||||
public function icon(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Performance => 'heroicon-o-star',
|
||||
self::Holiday => 'heroicon-o-gift',
|
||||
self::Retention => 'heroicon-o-hand-raised',
|
||||
self::Other => 'heroicon-o-banknotes',
|
||||
};
|
||||
}
|
||||
}
|
||||
39
app/Enums/DisciplinarySeverity.php
Normal file
39
app/Enums/DisciplinarySeverity.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum DisciplinarySeverity: string
|
||||
{
|
||||
case Low = 'low';
|
||||
case Medium = 'medium';
|
||||
case High = 'high';
|
||||
|
||||
public function label(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Low => 'Low',
|
||||
self::Medium => 'Medium',
|
||||
self::High => 'High',
|
||||
};
|
||||
}
|
||||
|
||||
public function color(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Low => 'info',
|
||||
self::Medium => 'warning',
|
||||
self::High => 'danger',
|
||||
};
|
||||
}
|
||||
|
||||
public function icon(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Low => 'heroicon-o-information-circle',
|
||||
self::Medium => 'heroicon-o-exclamation-triangle',
|
||||
self::High => 'heroicon-o-shield-exclamation',
|
||||
};
|
||||
}
|
||||
}
|
||||
47
app/Enums/DocumentType.php
Normal file
47
app/Enums/DocumentType.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum DocumentType: string
|
||||
{
|
||||
case Passport = 'passport';
|
||||
case Contract = 'contract';
|
||||
case MedicalCertificate = 'medical_certificate';
|
||||
case EducationCertificate = 'education_certificate';
|
||||
case Other = 'other';
|
||||
|
||||
public function label(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Passport => 'Passport',
|
||||
self::Contract => 'Contract',
|
||||
self::MedicalCertificate => 'Medical Certificate',
|
||||
self::EducationCertificate => 'Education Certificate',
|
||||
self::Other => 'Other',
|
||||
};
|
||||
}
|
||||
|
||||
public function color(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Passport => 'primary',
|
||||
self::Contract => 'success',
|
||||
self::MedicalCertificate => 'danger',
|
||||
self::EducationCertificate => 'info',
|
||||
self::Other => 'gray',
|
||||
};
|
||||
}
|
||||
|
||||
public function icon(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Passport => 'heroicon-o-identification',
|
||||
self::Contract => 'heroicon-o-document-text',
|
||||
self::MedicalCertificate => 'heroicon-o-heart',
|
||||
self::EducationCertificate => 'heroicon-o-academic-cap',
|
||||
self::Other => 'heroicon-o-folder',
|
||||
};
|
||||
}
|
||||
}
|
||||
43
app/Enums/EmploymentStatus.php
Normal file
43
app/Enums/EmploymentStatus.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum EmploymentStatus: string
|
||||
{
|
||||
case Active = 'active';
|
||||
case Inactive = 'inactive';
|
||||
case Terminated = 'terminated';
|
||||
case OnLeave = 'on_leave';
|
||||
|
||||
public function label(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Active => 'Active',
|
||||
self::Inactive => 'Inactive',
|
||||
self::Terminated => 'Terminated',
|
||||
self::OnLeave => 'On Leave',
|
||||
};
|
||||
}
|
||||
|
||||
public function color(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Active => 'success',
|
||||
self::Inactive => 'gray',
|
||||
self::Terminated => 'danger',
|
||||
self::OnLeave => 'warning',
|
||||
};
|
||||
}
|
||||
|
||||
public function icon(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Active => 'heroicon-o-check-circle',
|
||||
self::Inactive => 'heroicon-o-pause-circle',
|
||||
self::Terminated => 'heroicon-o-x-circle',
|
||||
self::OnLeave => 'heroicon-o-clock',
|
||||
};
|
||||
}
|
||||
}
|
||||
39
app/Enums/Gender.php
Normal file
39
app/Enums/Gender.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum Gender: string
|
||||
{
|
||||
case Male = 'male';
|
||||
case Female = 'female';
|
||||
case Other = 'other';
|
||||
|
||||
public function label(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Male => 'Male',
|
||||
self::Female => 'Female',
|
||||
self::Other => 'Other',
|
||||
};
|
||||
}
|
||||
|
||||
public function color(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Male => 'info',
|
||||
self::Female => 'pink',
|
||||
self::Other => 'gray',
|
||||
};
|
||||
}
|
||||
|
||||
public function icon(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Male => 'heroicon-o-user',
|
||||
self::Female => 'heroicon-o-user',
|
||||
self::Other => 'heroicon-o-users',
|
||||
};
|
||||
}
|
||||
}
|
||||
71
app/Enums/ImportType.php
Normal file
71
app/Enums/ImportType.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum ImportType: string
|
||||
{
|
||||
case Employees = 'employees';
|
||||
case Vacations = 'vacations';
|
||||
case Bonuses = 'bonuses';
|
||||
case Reports = 'reports';
|
||||
|
||||
public function label(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Employees => 'Employees',
|
||||
self::Vacations => 'Vacations',
|
||||
self::Bonuses => 'Bonuses',
|
||||
self::Reports => 'Disciplinary Reports',
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function fields(): array
|
||||
{
|
||||
return match ($this) {
|
||||
self::Employees => [
|
||||
'employee_number' => 'Employee Number',
|
||||
'full_name' => 'Full Name',
|
||||
'national_id' => 'National ID',
|
||||
'gender' => 'Gender',
|
||||
'birth_date' => 'Birth Date',
|
||||
'phone' => 'Phone',
|
||||
'address' => 'Address',
|
||||
'department' => 'Department',
|
||||
'position' => 'Position',
|
||||
'shift' => 'Shift',
|
||||
'employment_status' => 'Employment Status',
|
||||
'hire_date' => 'Hire Date',
|
||||
'notes' => 'Notes',
|
||||
],
|
||||
self::Vacations => [
|
||||
'employee_number' => 'Employee Number',
|
||||
'type' => 'Type',
|
||||
'start_date' => 'Start Date',
|
||||
'end_date' => 'End Date',
|
||||
'return_date' => 'Return Date',
|
||||
'days' => 'Days',
|
||||
'status' => 'Status',
|
||||
'reason' => 'Reason',
|
||||
],
|
||||
self::Bonuses => [
|
||||
'employee_number' => 'Employee Number',
|
||||
'bonus_date' => 'Bonus Date',
|
||||
'bonus_type' => 'Bonus Type',
|
||||
'amount' => 'Amount',
|
||||
'reason' => 'Reason',
|
||||
],
|
||||
self::Reports => [
|
||||
'employee_number' => 'Employee Number',
|
||||
'report_date' => 'Report Date',
|
||||
'title' => 'Title',
|
||||
'description' => 'Description',
|
||||
'severity' => 'Severity',
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
43
app/Enums/VacationType.php
Normal file
43
app/Enums/VacationType.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum VacationType: string
|
||||
{
|
||||
case Annual = 'annual';
|
||||
case Marriage = 'marriage';
|
||||
case Study = 'study';
|
||||
case Other = 'other';
|
||||
|
||||
public function label(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Annual => 'Annual',
|
||||
self::Marriage => 'Marriage',
|
||||
self::Study => 'Study',
|
||||
self::Other => 'Other',
|
||||
};
|
||||
}
|
||||
|
||||
public function color(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Annual => 'primary',
|
||||
self::Marriage => 'pink',
|
||||
self::Study => 'info',
|
||||
self::Other => 'gray',
|
||||
};
|
||||
}
|
||||
|
||||
public function icon(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Annual => 'heroicon-o-sun',
|
||||
self::Marriage => 'heroicon-o-heart',
|
||||
self::Study => 'heroicon-o-academic-cap',
|
||||
self::Other => 'heroicon-o-calendar-days',
|
||||
};
|
||||
}
|
||||
}
|
||||
63
app/Exports/BonusesExport.php
Normal file
63
app/Exports/BonusesExport.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Exports;
|
||||
|
||||
use App\Models\Bonus;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Maatwebsite\Excel\Concerns\FromQuery;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
use Maatwebsite\Excel\Concerns\WithMapping;
|
||||
|
||||
class BonusesExport implements FromQuery, WithHeadings, WithMapping
|
||||
{
|
||||
/**
|
||||
* @param array<int, int>|null $ids
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly ?array $ids = null,
|
||||
) {}
|
||||
|
||||
public function query(): Builder
|
||||
{
|
||||
$query = Bonus::query()->with('employee');
|
||||
|
||||
if ($this->ids !== null) {
|
||||
$query->whereIn('id', $this->ids);
|
||||
}
|
||||
|
||||
return $query->orderByDesc('bonus_date');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function headings(): array
|
||||
{
|
||||
return [
|
||||
'Employee Number',
|
||||
'Employee Name',
|
||||
'Bonus Date',
|
||||
'Bonus Type',
|
||||
'Amount',
|
||||
'Reason',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Bonus $bonus
|
||||
* @return array<int, mixed>
|
||||
*/
|
||||
public function map($bonus): array
|
||||
{
|
||||
return [
|
||||
$bonus->employee?->employee_number,
|
||||
$bonus->employee?->full_name,
|
||||
$bonus->bonus_date?->toDateString(),
|
||||
$bonus->bonus_type?->value,
|
||||
$bonus->amount,
|
||||
$bonus->reason,
|
||||
];
|
||||
}
|
||||
}
|
||||
80
app/Exports/EmployeesExport.php
Normal file
80
app/Exports/EmployeesExport.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Exports;
|
||||
|
||||
use App\Models\Employee;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Maatwebsite\Excel\Concerns\FromQuery;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
use Maatwebsite\Excel\Concerns\WithMapping;
|
||||
|
||||
class EmployeesExport implements FromQuery, WithHeadings, WithMapping
|
||||
{
|
||||
/**
|
||||
* @param array<int, int>|null $ids
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly ?array $ids = null,
|
||||
) {}
|
||||
|
||||
public function query(): Builder
|
||||
{
|
||||
$query = Employee::query()
|
||||
->with(['department', 'position', 'shift']);
|
||||
|
||||
if ($this->ids !== null) {
|
||||
$query->whereIn('id', $this->ids);
|
||||
}
|
||||
|
||||
return $query->orderBy('employee_number');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function headings(): array
|
||||
{
|
||||
return [
|
||||
'Employee Number',
|
||||
'Full Name',
|
||||
'National ID',
|
||||
'Gender',
|
||||
'Birth Date',
|
||||
'Phone',
|
||||
'Address',
|
||||
'Department',
|
||||
'Position',
|
||||
'Shift',
|
||||
'Employment Status',
|
||||
'Hire Date',
|
||||
'Termination Date',
|
||||
'Notes',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Employee $employee
|
||||
* @return array<int, mixed>
|
||||
*/
|
||||
public function map($employee): array
|
||||
{
|
||||
return [
|
||||
$employee->employee_number,
|
||||
$employee->full_name,
|
||||
$employee->national_id,
|
||||
$employee->gender?->value,
|
||||
$employee->birth_date?->toDateString(),
|
||||
$employee->phone,
|
||||
$employee->address,
|
||||
$employee->department?->name,
|
||||
$employee->position?->name,
|
||||
$employee->shift?->name,
|
||||
$employee->employment_status?->value,
|
||||
$employee->hire_date?->toDateString(),
|
||||
$employee->termination_date?->toDateString(),
|
||||
$employee->notes,
|
||||
];
|
||||
}
|
||||
}
|
||||
65
app/Exports/ReportsExport.php
Normal file
65
app/Exports/ReportsExport.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Exports;
|
||||
|
||||
use App\Models\DisciplinaryReport;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Maatwebsite\Excel\Concerns\FromQuery;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
use Maatwebsite\Excel\Concerns\WithMapping;
|
||||
|
||||
class ReportsExport implements FromQuery, WithHeadings, WithMapping
|
||||
{
|
||||
/**
|
||||
* @param array<int, int>|null $ids
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly ?array $ids = null,
|
||||
) {}
|
||||
|
||||
public function query(): Builder
|
||||
{
|
||||
$query = DisciplinaryReport::query()->with(['employee', 'creator']);
|
||||
|
||||
if ($this->ids !== null) {
|
||||
$query->whereIn('id', $this->ids);
|
||||
}
|
||||
|
||||
return $query->orderByDesc('report_date');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function headings(): array
|
||||
{
|
||||
return [
|
||||
'Employee Number',
|
||||
'Employee Name',
|
||||
'Report Date',
|
||||
'Title',
|
||||
'Description',
|
||||
'Severity',
|
||||
'Created By',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DisciplinaryReport $report
|
||||
* @return array<int, mixed>
|
||||
*/
|
||||
public function map($report): array
|
||||
{
|
||||
return [
|
||||
$report->employee?->employee_number,
|
||||
$report->employee?->full_name,
|
||||
$report->report_date?->toDateString(),
|
||||
$report->title,
|
||||
$report->description,
|
||||
$report->severity?->value,
|
||||
$report->creator?->name,
|
||||
];
|
||||
}
|
||||
}
|
||||
73
app/Exports/VacationsExport.php
Normal file
73
app/Exports/VacationsExport.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Exports;
|
||||
|
||||
use App\Models\Vacation;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Maatwebsite\Excel\Concerns\FromQuery;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
use Maatwebsite\Excel\Concerns\WithMapping;
|
||||
|
||||
class VacationsExport implements FromQuery, WithHeadings, WithMapping
|
||||
{
|
||||
/**
|
||||
* @param array<int, int>|null $ids
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly ?array $ids = null,
|
||||
) {}
|
||||
|
||||
public function query(): Builder
|
||||
{
|
||||
$query = Vacation::query()->with(['employee', 'approver']);
|
||||
|
||||
if ($this->ids !== null) {
|
||||
$query->whereIn('id', $this->ids);
|
||||
}
|
||||
|
||||
return $query->orderByDesc('start_date');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function headings(): array
|
||||
{
|
||||
return [
|
||||
'Employee Number',
|
||||
'Employee Name',
|
||||
'Type',
|
||||
'Start Date',
|
||||
'End Date',
|
||||
'Return Date',
|
||||
'Days',
|
||||
'Status',
|
||||
'Reason',
|
||||
'Approved By',
|
||||
'Approved At',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Vacation $vacation
|
||||
* @return array<int, mixed>
|
||||
*/
|
||||
public function map($vacation): array
|
||||
{
|
||||
return [
|
||||
$vacation->employee?->employee_number,
|
||||
$vacation->employee?->full_name,
|
||||
$vacation->type?->value,
|
||||
$vacation->start_date?->toDateString(),
|
||||
$vacation->end_date?->toDateString(),
|
||||
$vacation->return_date?->toDateString(),
|
||||
$vacation->days,
|
||||
$vacation->status?->value,
|
||||
$vacation->reason,
|
||||
$vacation->approver?->name,
|
||||
$vacation->approved_at?->toDateTimeString(),
|
||||
];
|
||||
}
|
||||
}
|
||||
42
app/Filament/Pages/Dashboard.php
Normal file
42
app/Filament/Pages/Dashboard.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Pages;
|
||||
|
||||
use App\Filament\Widgets\DepartmentDistributionChart;
|
||||
use App\Filament\Widgets\HrStatsOverviewWidget;
|
||||
use App\Filament\Widgets\MonthlyHiringChart;
|
||||
use App\Filament\Widgets\MonthlyLeaveChart;
|
||||
use App\Filament\Widgets\RecentReportsWidget;
|
||||
use App\Filament\Widgets\UpcomingBirthdaysWidget;
|
||||
use App\Filament\Widgets\UpcomingLeaveWidget;
|
||||
use Filament\Pages\Dashboard as BaseDashboard;
|
||||
|
||||
class Dashboard extends BaseDashboard
|
||||
{
|
||||
/**
|
||||
* @return array<class-string>
|
||||
*/
|
||||
public function getWidgets(): array
|
||||
{
|
||||
return [
|
||||
HrStatsOverviewWidget::class,
|
||||
RecentReportsWidget::class,
|
||||
UpcomingBirthdaysWidget::class,
|
||||
UpcomingLeaveWidget::class,
|
||||
MonthlyHiringChart::class,
|
||||
MonthlyLeaveChart::class,
|
||||
DepartmentDistributionChart::class,
|
||||
];
|
||||
}
|
||||
|
||||
public function getColumns(): int | array
|
||||
{
|
||||
return [
|
||||
'default' => 1,
|
||||
'md' => 2,
|
||||
'xl' => 3,
|
||||
];
|
||||
}
|
||||
}
|
||||
332
app/Filament/Pages/ImportWizard.php
Normal file
332
app/Filament/Pages/ImportWizard.php
Normal file
@@ -0,0 +1,332 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Pages;
|
||||
|
||||
use App\Enums\ImportType;
|
||||
use App\Jobs\ProcessImportJob;
|
||||
use App\Services\Import\ImportService;
|
||||
use BackedEnum;
|
||||
use Filament\Forms\Components\FileUpload;
|
||||
use Filament\Forms\Components\Placeholder;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Pages\Page;
|
||||
use Filament\Schemas\Components\Actions;
|
||||
use Filament\Schemas\Components\EmbeddedSchema;
|
||||
use Filament\Schemas\Components\Form;
|
||||
use Filament\Schemas\Components\Section;
|
||||
use Filament\Schemas\Components\Wizard;
|
||||
use Filament\Schemas\Components\Wizard\Step;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Enums\Alignment;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Illuminate\Contracts\Support\Htmlable;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\HtmlString;
|
||||
use UnitEnum;
|
||||
|
||||
class ImportWizard extends Page
|
||||
{
|
||||
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedArrowUpTray;
|
||||
|
||||
protected static string|UnitEnum|null $navigationGroup = 'System';
|
||||
|
||||
protected static ?string $navigationLabel = 'Import Wizard';
|
||||
|
||||
protected static ?int $navigationSort = 2;
|
||||
|
||||
protected static ?string $title = 'Import Wizard';
|
||||
|
||||
protected static ?string $slug = 'import-wizard';
|
||||
|
||||
/**
|
||||
* @var array<string, mixed>|null
|
||||
*/
|
||||
public ?array $data = [];
|
||||
|
||||
/** @var array<int, string> */
|
||||
public array $headers = [];
|
||||
|
||||
public ?string $storedFilePath = null;
|
||||
|
||||
/** @var array<string, mixed>|null */
|
||||
public ?array $importResult = null;
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->form->fill([
|
||||
'import_type' => ImportType::Employees->value,
|
||||
'column_mapping' => [],
|
||||
]);
|
||||
|
||||
$this->refreshImportResult();
|
||||
}
|
||||
|
||||
public function defaultForm(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->statePath('data')
|
||||
->columns(1);
|
||||
}
|
||||
|
||||
public function form(Schema $schema): Schema
|
||||
{
|
||||
return $schema->components([
|
||||
Wizard::make([
|
||||
Step::make('Upload')
|
||||
->description('Select import type and upload an Excel file')
|
||||
->schema([
|
||||
Select::make('import_type')
|
||||
->label('Import Type')
|
||||
->options(ImportType::class)
|
||||
->required()
|
||||
->live()
|
||||
->afterStateUpdated(fn () => $this->resetColumnMapping()),
|
||||
FileUpload::make('file')
|
||||
->label('Excel File')
|
||||
->disk(config('hr.file_uploads.disk'))
|
||||
->directory(config('hr.file_uploads.directory') . '/imports')
|
||||
->acceptedFileTypes([
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'application/vnd.ms-excel',
|
||||
'text/csv',
|
||||
])
|
||||
->required()
|
||||
->afterStateUpdated(fn () => $this->loadHeaders()),
|
||||
]),
|
||||
Step::make('Map Columns')
|
||||
->description('Match spreadsheet columns to system fields')
|
||||
->schema([
|
||||
Section::make('Column Mapping')
|
||||
->schema(fn (): array => $this->getColumnMappingFields()),
|
||||
]),
|
||||
Step::make('Preview')
|
||||
->description('Review the first 10 rows with validation')
|
||||
->schema([
|
||||
Placeholder::make('preview_table')
|
||||
->label('Preview')
|
||||
->content(fn (): HtmlString => new HtmlString($this->getPreviewHtml())),
|
||||
]),
|
||||
Step::make('Import')
|
||||
->description('Run the import and review results')
|
||||
->schema([
|
||||
Placeholder::make('import_results')
|
||||
->label('Import Results')
|
||||
->content(fn (): HtmlString => new HtmlString($this->getResultsHtml())),
|
||||
]),
|
||||
])
|
||||
->alpineSubmitHandler('$wire.runImport()')
|
||||
->submitAction(new HtmlString('<button type="submit" class="fi-btn fi-btn-primary">Start Import</button>'))
|
||||
->skippable(false),
|
||||
]);
|
||||
}
|
||||
|
||||
public function content(Schema $schema): Schema
|
||||
{
|
||||
return $schema->components([
|
||||
Form::make([EmbeddedSchema::make('form')])
|
||||
->id('import-wizard-form')
|
||||
->livewireSubmitHandler('runImport')
|
||||
->footer([
|
||||
Actions::make([])
|
||||
->alignment(Alignment::Start)
|
||||
->key('import-wizard-actions'),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
public function runImport(): void
|
||||
{
|
||||
$this->form->validate();
|
||||
|
||||
$filePath = $this->resolveStoredFilePath();
|
||||
|
||||
if ($filePath === null) {
|
||||
Notification::make()
|
||||
->title('Upload required')
|
||||
->body('Please upload an Excel file before importing.')
|
||||
->danger()
|
||||
->send();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$importType = ImportType::from($this->data['import_type']);
|
||||
$columnMapping = $this->data['column_mapping'] ?? [];
|
||||
|
||||
ProcessImportJob::dispatch(
|
||||
$importType,
|
||||
$filePath,
|
||||
$columnMapping,
|
||||
Auth::id(),
|
||||
);
|
||||
|
||||
Notification::make()
|
||||
->title('Import queued')
|
||||
->body('Your import has been queued and will be processed shortly.')
|
||||
->success()
|
||||
->send();
|
||||
}
|
||||
|
||||
public function refreshImportResult(): void
|
||||
{
|
||||
$result = ProcessImportJob::getCachedResult(Auth::id());
|
||||
$this->importResult = $result?->toArray();
|
||||
}
|
||||
|
||||
public function loadHeaders(): void
|
||||
{
|
||||
$path = $this->resolveStoredFilePath();
|
||||
|
||||
if ($path === null) {
|
||||
$this->headers = [];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->headers = app(ImportService::class)->readHeaders($path);
|
||||
$this->resetColumnMapping();
|
||||
}
|
||||
|
||||
protected function resetColumnMapping(): void
|
||||
{
|
||||
$this->data['column_mapping'] = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, Select>
|
||||
*/
|
||||
protected function getColumnMappingFields(): array
|
||||
{
|
||||
if ($this->headers === []) {
|
||||
return [
|
||||
Placeholder::make('mapping_hint')
|
||||
->content('Upload a file in step 1 to load column headers.'),
|
||||
];
|
||||
}
|
||||
|
||||
$importType = ImportType::from($this->data['import_type'] ?? ImportType::Employees->value);
|
||||
$headerOptions = array_combine($this->headers, $this->headers);
|
||||
|
||||
return collect($importType->fields())
|
||||
->map(function (string $label, string $field) use ($headerOptions): Select {
|
||||
return Select::make("column_mapping.{$field}")
|
||||
->label($label)
|
||||
->options($headerOptions)
|
||||
->searchable()
|
||||
->nullable();
|
||||
})
|
||||
->values()
|
||||
->all();
|
||||
}
|
||||
|
||||
protected function getPreviewHtml(): string
|
||||
{
|
||||
$path = $this->resolveStoredFilePath();
|
||||
|
||||
if ($path === null) {
|
||||
return '<p class="text-sm text-gray-500">Upload a file to preview rows.</p>';
|
||||
}
|
||||
|
||||
$importType = ImportType::from($this->data['import_type'] ?? ImportType::Employees->value);
|
||||
$importService = app(ImportService::class);
|
||||
$rows = $importService->readRows($path, 10);
|
||||
$mappedRows = $importService->mapRows($rows, $this->data['column_mapping'] ?? []);
|
||||
$validation = $importService->validatePreview($importType, $mappedRows);
|
||||
|
||||
if ($mappedRows === []) {
|
||||
return '<p class="text-sm text-gray-500">No rows found in the uploaded file.</p>';
|
||||
}
|
||||
|
||||
$fields = array_keys($importType->fields());
|
||||
$html = '<div class="overflow-x-auto"><table class="fi-ta-table w-full text-sm"><thead><tr>';
|
||||
$html .= '<th class="px-3 py-2 text-left">Row</th>';
|
||||
|
||||
foreach ($fields as $field) {
|
||||
$html .= '<th class="px-3 py-2 text-left">' . e($importType->fields()[$field]) . '</th>';
|
||||
}
|
||||
|
||||
$html .= '<th class="px-3 py-2 text-left">Validation</th></tr></thead><tbody>';
|
||||
|
||||
foreach ($mappedRows as $index => $row) {
|
||||
$errors = $validation[$index]['errors'] ?? [];
|
||||
$html .= '<tr class="border-t border-gray-200 dark:border-gray-700">';
|
||||
$html .= '<td class="px-3 py-2">' . ($index + 2) . '</td>';
|
||||
|
||||
foreach ($fields as $field) {
|
||||
$html .= '<td class="px-3 py-2">' . e((string) ($row[$field] ?? '—')) . '</td>';
|
||||
}
|
||||
|
||||
$html .= '<td class="px-3 py-2">';
|
||||
|
||||
if ($errors === []) {
|
||||
$html .= '<span class="text-success-600">Valid</span>';
|
||||
} else {
|
||||
$html .= '<span class="text-danger-600">' . e(implode(' ', $errors)) . '</span>';
|
||||
}
|
||||
|
||||
$html .= '</td></tr>';
|
||||
}
|
||||
|
||||
$html .= '</tbody></table></div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
protected function getResultsHtml(): string
|
||||
{
|
||||
$this->refreshImportResult();
|
||||
|
||||
if ($this->importResult === null) {
|
||||
return '<p class="text-sm text-gray-500">Submit the import to see results here after processing completes.</p>';
|
||||
}
|
||||
|
||||
$html = '<div class="space-y-2 text-sm">';
|
||||
$html .= '<p><strong>Total rows:</strong> ' . $this->importResult['total'] . '</p>';
|
||||
$html .= '<p><strong>Imported:</strong> ' . $this->importResult['imported'] . '</p>';
|
||||
$html .= '<p><strong>Skipped (duplicates):</strong> ' . $this->importResult['skipped'] . '</p>';
|
||||
$html .= '<p><strong>Failed:</strong> ' . $this->importResult['failed'] . '</p>';
|
||||
|
||||
if (($this->importResult['errors'] ?? []) !== []) {
|
||||
$html .= '<div class="mt-3"><strong>Errors:</strong><ul class="list-disc ps-5">';
|
||||
|
||||
foreach ($this->importResult['errors'] as $error) {
|
||||
$html .= '<li>' . e($error) . '</li>';
|
||||
}
|
||||
|
||||
$html .= '</ul></div>';
|
||||
}
|
||||
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
protected function resolveStoredFilePath(): ?string
|
||||
{
|
||||
$file = $this->data['file'] ?? null;
|
||||
|
||||
if ($file === null || $file === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$relativePath = is_array($file) ? ($file[0] ?? null) : $file;
|
||||
|
||||
if ($relativePath === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$disk = Storage::disk(config('hr.file_uploads.disk'));
|
||||
$this->storedFilePath = $disk->path($relativePath);
|
||||
|
||||
return $this->storedFilePath;
|
||||
}
|
||||
|
||||
public function getTitle(): string|Htmlable
|
||||
{
|
||||
return 'Import Wizard';
|
||||
}
|
||||
}
|
||||
89
app/Filament/Resources/ActivityLogs/ActivityLogResource.php
Normal file
89
app/Filament/Resources/ActivityLogs/ActivityLogResource.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\ActivityLogs;
|
||||
|
||||
use App\Filament\Resources\ActivityLogs\Pages\ListActivityLogs;
|
||||
use App\Filament\Resources\ActivityLogs\Pages\ViewActivityLog;
|
||||
use App\Filament\Resources\ActivityLogs\Schemas\ActivityLogInfolist;
|
||||
use App\Filament\Resources\ActivityLogs\Tables\ActivityLogsTable;
|
||||
use BackedEnum;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Tables\Table;
|
||||
use Spatie\Activitylog\Models\Activity;
|
||||
use UnitEnum;
|
||||
|
||||
class ActivityLogResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Activity::class;
|
||||
|
||||
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedClipboardDocumentList;
|
||||
|
||||
protected static string|UnitEnum|null $navigationGroup = 'System';
|
||||
|
||||
protected static ?int $navigationSort = 3;
|
||||
|
||||
protected static ?string $navigationLabel = 'Audit Log';
|
||||
|
||||
protected static ?string $modelLabel = 'Activity Log';
|
||||
|
||||
protected static ?string $pluralModelLabel = 'Activity Logs';
|
||||
|
||||
protected static ?string $slug = 'activity-logs';
|
||||
|
||||
public static function form(Schema $schema): Schema
|
||||
{
|
||||
return $schema;
|
||||
}
|
||||
|
||||
public static function infolist(Schema $schema): Schema
|
||||
{
|
||||
return ActivityLogInfolist::configure($schema);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return ActivityLogsTable::configure($table);
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ListActivityLogs::route('/'),
|
||||
'view' => ViewActivityLog::route('/{record}'),
|
||||
];
|
||||
}
|
||||
|
||||
public static function canCreate(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function canEdit($record): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function canDelete($record): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function canForceDelete($record): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function canRestore($record): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\ActivityLogs\Pages;
|
||||
|
||||
use App\Filament\Resources\ActivityLogs\ActivityLogResource;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListActivityLogs extends ListRecords
|
||||
{
|
||||
protected static string $resource = ActivityLogResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\ActivityLogs\Pages;
|
||||
|
||||
use App\Filament\Resources\ActivityLogs\ActivityLogResource;
|
||||
use Filament\Resources\Pages\ViewRecord;
|
||||
|
||||
class ViewActivityLog extends ViewRecord
|
||||
{
|
||||
protected static string $resource = ActivityLogResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\ActivityLogs\Schemas;
|
||||
|
||||
use Filament\Infolists\Components\KeyValueEntry;
|
||||
use Filament\Infolists\Components\TextEntry;
|
||||
use Filament\Schemas\Components\Section;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class ActivityLogInfolist
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
Section::make('Activity Details')
|
||||
->schema([
|
||||
TextEntry::make('created_at')
|
||||
->label('Date')
|
||||
->dateTime(),
|
||||
TextEntry::make('description'),
|
||||
TextEntry::make('event')
|
||||
->badge(),
|
||||
TextEntry::make('log_name')
|
||||
->label('Log Name'),
|
||||
TextEntry::make('subject_type')
|
||||
->label('Subject Type')
|
||||
->formatStateUsing(fn (?string $state): string => $state ? class_basename($state) : '—'),
|
||||
TextEntry::make('subject_id')
|
||||
->label('Subject ID'),
|
||||
TextEntry::make('causer.name')
|
||||
->label('Causer'),
|
||||
KeyValueEntry::make('properties.attributes')
|
||||
->label('Changes')
|
||||
->visible(fn ($record): bool => filled($record->properties['attributes'] ?? null)),
|
||||
KeyValueEntry::make('properties.old')
|
||||
->label('Previous Values')
|
||||
->visible(fn ($record): bool => filled($record->properties['old'] ?? null)),
|
||||
])
|
||||
->columns(2),
|
||||
]);
|
||||
}
|
||||
}
|
||||
100
app/Filament/Resources/ActivityLogs/Tables/ActivityLogsTable.php
Normal file
100
app/Filament/Resources/ActivityLogs/Tables/ActivityLogsTable.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\ActivityLogs\Tables;
|
||||
|
||||
use App\Models\Bonus;
|
||||
use App\Models\Department;
|
||||
use App\Models\DisciplinaryReport;
|
||||
use App\Models\Employee;
|
||||
use App\Models\User;
|
||||
use App\Models\Vacation;
|
||||
use Filament\Actions\ViewAction;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\Filter;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class ActivityLogsTable
|
||||
{
|
||||
public static function configure(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
TextColumn::make('created_at')
|
||||
->label('Date')
|
||||
->dateTime()
|
||||
->sortable(),
|
||||
TextColumn::make('description')
|
||||
->searchable()
|
||||
->limit(50),
|
||||
TextColumn::make('event')
|
||||
->badge()
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('subject_type')
|
||||
->label('Subject Type')
|
||||
->formatStateUsing(fn (?string $state): string => $state ? class_basename($state) : '—')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('subject_id')
|
||||
->label('Subject ID')
|
||||
->sortable(),
|
||||
TextColumn::make('causer.name')
|
||||
->label('Causer')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('log_name')
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
])
|
||||
->defaultSort('created_at', 'desc')
|
||||
->filters([
|
||||
SelectFilter::make('subject_type')
|
||||
->label('Subject Type')
|
||||
->options([
|
||||
Employee::class => 'Employee',
|
||||
Vacation::class => 'Vacation',
|
||||
Bonus::class => 'Bonus',
|
||||
DisciplinaryReport::class => 'Disciplinary Report',
|
||||
Department::class => 'Department',
|
||||
User::class => 'User',
|
||||
]),
|
||||
SelectFilter::make('event')
|
||||
->options(fn (): array => \Spatie\Activitylog\Models\Activity::query()
|
||||
->whereNotNull('event')
|
||||
->distinct()
|
||||
->pluck('event', 'event')
|
||||
->all()),
|
||||
SelectFilter::make('causer')
|
||||
->label('Causer')
|
||||
->relationship('causer', 'name')
|
||||
->searchable()
|
||||
->preload(),
|
||||
Filter::make('created_at')
|
||||
->schema([
|
||||
DatePicker::make('from')
|
||||
->label('From'),
|
||||
DatePicker::make('until')
|
||||
->label('Until'),
|
||||
])
|
||||
->query(function (Builder $query, array $data): Builder {
|
||||
return $query
|
||||
->when(
|
||||
$data['from'] ?? null,
|
||||
fn (Builder $query, string $date): Builder => $query->whereDate('created_at', '>=', $date),
|
||||
)
|
||||
->when(
|
||||
$data['until'] ?? null,
|
||||
fn (Builder $query, string $date): Builder => $query->whereDate('created_at', '<=', $date),
|
||||
);
|
||||
}),
|
||||
])
|
||||
->recordActions([
|
||||
ViewAction::make(),
|
||||
])
|
||||
->toolbarActions([]);
|
||||
}
|
||||
}
|
||||
77
app/Filament/Resources/Bonuses/BonusResource.php
Normal file
77
app/Filament/Resources/Bonuses/BonusResource.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\Bonuses;
|
||||
|
||||
use App\Filament\Resources\Bonuses\Pages\CreateBonus;
|
||||
use App\Filament\Resources\Bonuses\Pages\EditBonus;
|
||||
use App\Filament\Resources\Bonuses\Pages\ListBonuses;
|
||||
use App\Filament\Resources\Bonuses\Pages\ViewBonus;
|
||||
use App\Filament\Resources\Bonuses\Schemas\BonusForm;
|
||||
use App\Filament\Resources\Bonuses\Schemas\BonusInfolist;
|
||||
use App\Filament\Resources\Bonuses\Tables\BonusesTable;
|
||||
use App\Models\Bonus;
|
||||
use BackedEnum;
|
||||
use UnitEnum;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\SoftDeletingScope;
|
||||
|
||||
class BonusResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Bonus::class;
|
||||
|
||||
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedCurrencyDollar;
|
||||
|
||||
protected static string | UnitEnum | null $navigationGroup = 'Records';
|
||||
|
||||
protected static ?int $navigationSort = 3;
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'reason';
|
||||
|
||||
protected static bool $isGloballySearchable = false;
|
||||
|
||||
public static function form(Schema $schema): Schema
|
||||
{
|
||||
return BonusForm::configure($schema);
|
||||
}
|
||||
|
||||
public static function infolist(Schema $schema): Schema
|
||||
{
|
||||
return BonusInfolist::configure($schema);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return BonusesTable::configure($table);
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ListBonuses::route('/'),
|
||||
'create' => CreateBonus::route('/create'),
|
||||
'view' => ViewBonus::route('/{record}'),
|
||||
'edit' => EditBonus::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
|
||||
public static function getRecordRouteBindingEloquentQuery(): Builder
|
||||
{
|
||||
return parent::getRecordRouteBindingEloquentQuery()
|
||||
->withoutGlobalScopes([
|
||||
SoftDeletingScope::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
11
app/Filament/Resources/Bonuses/Pages/CreateBonus.php
Normal file
11
app/Filament/Resources/Bonuses/Pages/CreateBonus.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Bonuses\Pages;
|
||||
|
||||
use App\Filament\Resources\Bonuses\BonusResource;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateBonus extends CreateRecord
|
||||
{
|
||||
protected static string $resource = BonusResource::class;
|
||||
}
|
||||
25
app/Filament/Resources/Bonuses/Pages/EditBonus.php
Normal file
25
app/Filament/Resources/Bonuses/Pages/EditBonus.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Bonuses\Pages;
|
||||
|
||||
use App\Filament\Resources\Bonuses\BonusResource;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\ForceDeleteAction;
|
||||
use Filament\Actions\RestoreAction;
|
||||
use Filament\Actions\ViewAction;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditBonus extends EditRecord
|
||||
{
|
||||
protected static string $resource = BonusResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
ViewAction::make(),
|
||||
DeleteAction::make(),
|
||||
ForceDeleteAction::make(),
|
||||
RestoreAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
24
app/Filament/Resources/Bonuses/Pages/ListBonuses.php
Normal file
24
app/Filament/Resources/Bonuses/Pages/ListBonuses.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\Bonuses\Pages;
|
||||
|
||||
use App\Exports\BonusesExport;
|
||||
use App\Filament\Resources\Bonuses\BonusResource;
|
||||
use App\Filament\Support\ExportExcelAction;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListBonuses extends ListRecords
|
||||
{
|
||||
protected static string $resource = BonusResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
ExportExcelAction::make('export', BonusesExport::class, 'bonuses.xlsx'),
|
||||
CreateAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
19
app/Filament/Resources/Bonuses/Pages/ViewBonus.php
Normal file
19
app/Filament/Resources/Bonuses/Pages/ViewBonus.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Bonuses\Pages;
|
||||
|
||||
use App\Filament\Resources\Bonuses\BonusResource;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Resources\Pages\ViewRecord;
|
||||
|
||||
class ViewBonus extends ViewRecord
|
||||
{
|
||||
protected static string $resource = BonusResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
EditAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
38
app/Filament/Resources/Bonuses/Schemas/BonusForm.php
Normal file
38
app/Filament/Resources/Bonuses/Schemas/BonusForm.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Bonuses\Schemas;
|
||||
|
||||
use App\Enums\BonusType;
|
||||
use App\Filament\Support\HrForm;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Components\Textarea;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class BonusForm
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
HrForm::employeeSelect(),
|
||||
DatePicker::make('bonus_date')
|
||||
->required()
|
||||
->default(now()),
|
||||
Select::make('bonus_type')
|
||||
->options(BonusType::class)
|
||||
->required()
|
||||
->native(false),
|
||||
TextInput::make('amount')
|
||||
->required()
|
||||
->numeric()
|
||||
->prefix('TMT')
|
||||
->minValue(0)
|
||||
->step(0.01),
|
||||
Textarea::make('reason')
|
||||
->rows(3)
|
||||
->columnSpanFull(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
37
app/Filament/Resources/Bonuses/Schemas/BonusInfolist.php
Normal file
37
app/Filament/Resources/Bonuses/Schemas/BonusInfolist.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Bonuses\Schemas;
|
||||
|
||||
use App\Models\Bonus;
|
||||
use Filament\Infolists\Components\TextEntry;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class BonusInfolist
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
TextEntry::make('employee.id')
|
||||
->label('Employee'),
|
||||
TextEntry::make('bonus_date')
|
||||
->date(),
|
||||
TextEntry::make('bonus_type')
|
||||
->badge(),
|
||||
TextEntry::make('amount')
|
||||
->numeric(),
|
||||
TextEntry::make('reason')
|
||||
->placeholder('-')
|
||||
->columnSpanFull(),
|
||||
TextEntry::make('created_at')
|
||||
->dateTime()
|
||||
->placeholder('-'),
|
||||
TextEntry::make('updated_at')
|
||||
->dateTime()
|
||||
->placeholder('-'),
|
||||
TextEntry::make('deleted_at')
|
||||
->dateTime()
|
||||
->visible(fn (Bonus $record): bool => $record->trashed()),
|
||||
]);
|
||||
}
|
||||
}
|
||||
76
app/Filament/Resources/Bonuses/Tables/BonusesTable.php
Normal file
76
app/Filament/Resources/Bonuses/Tables/BonusesTable.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Bonuses\Tables;
|
||||
|
||||
use App\Enums\BonusType;
|
||||
use App\Filament\Support\ExportExcelAction;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ForceDeleteBulkAction;
|
||||
use Filament\Actions\RestoreBulkAction;
|
||||
use Filament\Actions\ViewAction;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use Filament\Tables\Filters\TrashedFilter;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class BonusesTable
|
||||
{
|
||||
public static function configure(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
TextColumn::make('employee.full_name')
|
||||
->label('Employee')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('bonus_date')
|
||||
->date()
|
||||
->sortable(),
|
||||
TextColumn::make('bonus_type')
|
||||
->label('Type')
|
||||
->badge()
|
||||
->color(fn (BonusType $state): string => $state->color())
|
||||
->formatStateUsing(fn (BonusType $state): string => $state->label())
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('amount')
|
||||
->money('TMT')
|
||||
->sortable(),
|
||||
TextColumn::make('reason')
|
||||
->limit(40)
|
||||
->toggleable(),
|
||||
TextColumn::make('created_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
TextColumn::make('updated_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
TextColumn::make('deleted_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
])
|
||||
->filters([
|
||||
SelectFilter::make('bonus_type')
|
||||
->label('Type')
|
||||
->options(BonusType::class),
|
||||
TrashedFilter::make(),
|
||||
])
|
||||
->recordActions([
|
||||
ViewAction::make(),
|
||||
EditAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
ExportExcelAction::bulk('exportSelected', \App\Exports\BonusesExport::class, 'bonuses.xlsx'),
|
||||
DeleteBulkAction::make(),
|
||||
ForceDeleteBulkAction::make(),
|
||||
RestoreBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
77
app/Filament/Resources/Departments/DepartmentResource.php
Normal file
77
app/Filament/Resources/Departments/DepartmentResource.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\Departments;
|
||||
|
||||
use App\Filament\Resources\Departments\Pages\CreateDepartment;
|
||||
use App\Filament\Resources\Departments\Pages\EditDepartment;
|
||||
use App\Filament\Resources\Departments\Pages\ListDepartments;
|
||||
use App\Filament\Resources\Departments\Pages\ViewDepartment;
|
||||
use App\Filament\Resources\Departments\Schemas\DepartmentForm;
|
||||
use App\Filament\Resources\Departments\Schemas\DepartmentInfolist;
|
||||
use App\Filament\Resources\Departments\Tables\DepartmentsTable;
|
||||
use App\Models\Department;
|
||||
use BackedEnum;
|
||||
use UnitEnum;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\SoftDeletingScope;
|
||||
|
||||
class DepartmentResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Department::class;
|
||||
|
||||
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedBuildingOffice2;
|
||||
|
||||
protected static string | UnitEnum | null $navigationGroup = 'Organization';
|
||||
|
||||
protected static ?int $navigationSort = 1;
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'name';
|
||||
|
||||
protected static bool $isGloballySearchable = false;
|
||||
|
||||
public static function form(Schema $schema): Schema
|
||||
{
|
||||
return DepartmentForm::configure($schema);
|
||||
}
|
||||
|
||||
public static function infolist(Schema $schema): Schema
|
||||
{
|
||||
return DepartmentInfolist::configure($schema);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return DepartmentsTable::configure($table);
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ListDepartments::route('/'),
|
||||
'create' => CreateDepartment::route('/create'),
|
||||
'view' => ViewDepartment::route('/{record}'),
|
||||
'edit' => EditDepartment::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
|
||||
public static function getRecordRouteBindingEloquentQuery(): Builder
|
||||
{
|
||||
return parent::getRecordRouteBindingEloquentQuery()
|
||||
->withoutGlobalScopes([
|
||||
SoftDeletingScope::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Departments\Pages;
|
||||
|
||||
use App\Filament\Resources\Departments\DepartmentResource;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateDepartment extends CreateRecord
|
||||
{
|
||||
protected static string $resource = DepartmentResource::class;
|
||||
}
|
||||
25
app/Filament/Resources/Departments/Pages/EditDepartment.php
Normal file
25
app/Filament/Resources/Departments/Pages/EditDepartment.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Departments\Pages;
|
||||
|
||||
use App\Filament\Resources\Departments\DepartmentResource;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\ForceDeleteAction;
|
||||
use Filament\Actions\RestoreAction;
|
||||
use Filament\Actions\ViewAction;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditDepartment extends EditRecord
|
||||
{
|
||||
protected static string $resource = DepartmentResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
ViewAction::make(),
|
||||
DeleteAction::make(),
|
||||
ForceDeleteAction::make(),
|
||||
RestoreAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
19
app/Filament/Resources/Departments/Pages/ListDepartments.php
Normal file
19
app/Filament/Resources/Departments/Pages/ListDepartments.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Departments\Pages;
|
||||
|
||||
use App\Filament\Resources\Departments\DepartmentResource;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListDepartments extends ListRecords
|
||||
{
|
||||
protected static string $resource = DepartmentResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
CreateAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
19
app/Filament/Resources/Departments/Pages/ViewDepartment.php
Normal file
19
app/Filament/Resources/Departments/Pages/ViewDepartment.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Departments\Pages;
|
||||
|
||||
use App\Filament\Resources\Departments\DepartmentResource;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Resources\Pages\ViewRecord;
|
||||
|
||||
class ViewDepartment extends ViewRecord
|
||||
{
|
||||
protected static string $resource = DepartmentResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
EditAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Departments\Schemas;
|
||||
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Components\Textarea;
|
||||
use Filament\Forms\Components\Toggle;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class DepartmentForm
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
TextInput::make('name')
|
||||
->required()
|
||||
->maxLength(255),
|
||||
TextInput::make('code')
|
||||
->required()
|
||||
->maxLength(50)
|
||||
->unique(ignoreRecord: true),
|
||||
Textarea::make('description')
|
||||
->rows(3)
|
||||
->columnSpanFull(),
|
||||
Toggle::make('is_active')
|
||||
->label('Active')
|
||||
->default(true)
|
||||
->required(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Departments\Schemas;
|
||||
|
||||
use App\Models\Department;
|
||||
use Filament\Infolists\Components\IconEntry;
|
||||
use Filament\Infolists\Components\TextEntry;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class DepartmentInfolist
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
TextEntry::make('name'),
|
||||
TextEntry::make('code'),
|
||||
TextEntry::make('description')
|
||||
->placeholder('-')
|
||||
->columnSpanFull(),
|
||||
IconEntry::make('is_active')
|
||||
->boolean(),
|
||||
TextEntry::make('created_at')
|
||||
->dateTime()
|
||||
->placeholder('-'),
|
||||
TextEntry::make('updated_at')
|
||||
->dateTime()
|
||||
->placeholder('-'),
|
||||
TextEntry::make('deleted_at')
|
||||
->dateTime()
|
||||
->visible(fn (Department $record): bool => $record->trashed()),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Departments\Tables;
|
||||
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ForceDeleteBulkAction;
|
||||
use Filament\Actions\RestoreBulkAction;
|
||||
use Filament\Actions\ViewAction;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\TernaryFilter;
|
||||
use Filament\Tables\Filters\TrashedFilter;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class DepartmentsTable
|
||||
{
|
||||
public static function configure(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
TextColumn::make('name')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('code')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('description')
|
||||
->limit(50)
|
||||
->toggleable(),
|
||||
TextColumn::make('is_active')
|
||||
->label('Status')
|
||||
->badge()
|
||||
->formatStateUsing(fn (bool $state): string => $state ? 'Active' : 'Inactive')
|
||||
->color(fn (bool $state): string => $state ? 'success' : 'danger')
|
||||
->sortable(),
|
||||
TextColumn::make('created_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
TextColumn::make('updated_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
TextColumn::make('deleted_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
])
|
||||
->filters([
|
||||
TernaryFilter::make('is_active')
|
||||
->label('Status')
|
||||
->placeholder('All departments')
|
||||
->trueLabel('Active')
|
||||
->falseLabel('Inactive'),
|
||||
TrashedFilter::make(),
|
||||
])
|
||||
->recordActions([
|
||||
ViewAction::make(),
|
||||
EditAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
ForceDeleteBulkAction::make(),
|
||||
RestoreBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\DisciplinaryReports;
|
||||
|
||||
use App\Filament\Resources\DisciplinaryReports\Pages\CreateDisciplinaryReport;
|
||||
use App\Filament\Resources\DisciplinaryReports\Pages\EditDisciplinaryReport;
|
||||
use App\Filament\Resources\DisciplinaryReports\Pages\ListDisciplinaryReports;
|
||||
use App\Filament\Resources\DisciplinaryReports\Pages\ViewDisciplinaryReport;
|
||||
use App\Filament\Resources\DisciplinaryReports\Schemas\DisciplinaryReportForm;
|
||||
use App\Filament\Resources\DisciplinaryReports\Schemas\DisciplinaryReportInfolist;
|
||||
use App\Filament\Resources\DisciplinaryReports\Tables\DisciplinaryReportsTable;
|
||||
use App\Models\DisciplinaryReport;
|
||||
use BackedEnum;
|
||||
use UnitEnum;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\SoftDeletingScope;
|
||||
|
||||
class DisciplinaryReportResource extends Resource
|
||||
{
|
||||
protected static ?string $model = DisciplinaryReport::class;
|
||||
|
||||
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedExclamationTriangle;
|
||||
|
||||
protected static string | UnitEnum | null $navigationGroup = 'Records';
|
||||
|
||||
protected static ?int $navigationSort = 1;
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'title';
|
||||
|
||||
protected static bool $isGloballySearchable = false;
|
||||
|
||||
public static function form(Schema $schema): Schema
|
||||
{
|
||||
return DisciplinaryReportForm::configure($schema);
|
||||
}
|
||||
|
||||
public static function infolist(Schema $schema): Schema
|
||||
{
|
||||
return DisciplinaryReportInfolist::configure($schema);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return DisciplinaryReportsTable::configure($table);
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ListDisciplinaryReports::route('/'),
|
||||
'create' => CreateDisciplinaryReport::route('/create'),
|
||||
'view' => ViewDisciplinaryReport::route('/{record}'),
|
||||
'edit' => EditDisciplinaryReport::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
|
||||
public static function getRecordRouteBindingEloquentQuery(): Builder
|
||||
{
|
||||
return parent::getRecordRouteBindingEloquentQuery()
|
||||
->withoutGlobalScopes([
|
||||
SoftDeletingScope::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\DisciplinaryReports\Pages;
|
||||
|
||||
use App\Filament\Resources\DisciplinaryReports\DisciplinaryReportResource;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateDisciplinaryReport extends CreateRecord
|
||||
{
|
||||
protected static string $resource = DisciplinaryReportResource::class;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\DisciplinaryReports\Pages;
|
||||
|
||||
use App\Filament\Resources\DisciplinaryReports\DisciplinaryReportResource;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\ForceDeleteAction;
|
||||
use Filament\Actions\RestoreAction;
|
||||
use Filament\Actions\ViewAction;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditDisciplinaryReport extends EditRecord
|
||||
{
|
||||
protected static string $resource = DisciplinaryReportResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
ViewAction::make(),
|
||||
DeleteAction::make(),
|
||||
ForceDeleteAction::make(),
|
||||
RestoreAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\DisciplinaryReports\Pages;
|
||||
|
||||
use App\Exports\ReportsExport;
|
||||
use App\Filament\Resources\DisciplinaryReports\DisciplinaryReportResource;
|
||||
use App\Filament\Support\ExportExcelAction;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListDisciplinaryReports extends ListRecords
|
||||
{
|
||||
protected static string $resource = DisciplinaryReportResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
ExportExcelAction::make('export', ReportsExport::class, 'disciplinary-reports.xlsx'),
|
||||
CreateAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\DisciplinaryReports\Pages;
|
||||
|
||||
use App\Filament\Resources\DisciplinaryReports\DisciplinaryReportResource;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Resources\Pages\ViewRecord;
|
||||
|
||||
class ViewDisciplinaryReport extends ViewRecord
|
||||
{
|
||||
protected static string $resource = DisciplinaryReportResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
EditAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\DisciplinaryReports\Schemas;
|
||||
|
||||
use App\Enums\DisciplinarySeverity;
|
||||
use App\Filament\Support\HrForm;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Components\Textarea;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class DisciplinaryReportForm
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
HrForm::employeeSelect(),
|
||||
DatePicker::make('report_date')
|
||||
->required()
|
||||
->default(now()),
|
||||
TextInput::make('title')
|
||||
->required()
|
||||
->maxLength(255),
|
||||
Textarea::make('description')
|
||||
->required()
|
||||
->rows(4)
|
||||
->columnSpanFull(),
|
||||
Select::make('severity')
|
||||
->options(DisciplinarySeverity::class)
|
||||
->required()
|
||||
->native(false),
|
||||
HrForm::fileUpload('attachment_path')
|
||||
->label('Attachment')
|
||||
->acceptedFileTypes(['application/pdf', 'image/*'])
|
||||
->maxSize(10240),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\DisciplinaryReports\Schemas;
|
||||
|
||||
use App\Models\DisciplinaryReport;
|
||||
use Filament\Infolists\Components\TextEntry;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class DisciplinaryReportInfolist
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
TextEntry::make('employee.id')
|
||||
->label('Employee'),
|
||||
TextEntry::make('report_date')
|
||||
->date(),
|
||||
TextEntry::make('title'),
|
||||
TextEntry::make('description')
|
||||
->columnSpanFull(),
|
||||
TextEntry::make('severity')
|
||||
->badge(),
|
||||
TextEntry::make('attachment_path')
|
||||
->placeholder('-'),
|
||||
TextEntry::make('created_by')
|
||||
->numeric()
|
||||
->placeholder('-'),
|
||||
TextEntry::make('created_at')
|
||||
->dateTime()
|
||||
->placeholder('-'),
|
||||
TextEntry::make('updated_at')
|
||||
->dateTime()
|
||||
->placeholder('-'),
|
||||
TextEntry::make('deleted_at')
|
||||
->dateTime()
|
||||
->visible(fn (DisciplinaryReport $record): bool => $record->trashed()),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\DisciplinaryReports\Tables;
|
||||
|
||||
use App\Enums\DisciplinarySeverity;
|
||||
use App\Filament\Support\ExportExcelAction;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ForceDeleteBulkAction;
|
||||
use Filament\Actions\RestoreBulkAction;
|
||||
use Filament\Actions\ViewAction;
|
||||
use Filament\Tables\Columns\IconColumn;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use Filament\Tables\Filters\TrashedFilter;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class DisciplinaryReportsTable
|
||||
{
|
||||
public static function configure(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
TextColumn::make('employee.full_name')
|
||||
->label('Employee')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('report_date')
|
||||
->date()
|
||||
->sortable(),
|
||||
TextColumn::make('title')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('severity')
|
||||
->badge()
|
||||
->color(fn (DisciplinarySeverity $state): string => $state->color())
|
||||
->formatStateUsing(fn (DisciplinarySeverity $state): string => $state->label())
|
||||
->searchable()
|
||||
->sortable(),
|
||||
IconColumn::make('attachment_path')
|
||||
->label('Attachment')
|
||||
->boolean()
|
||||
->trueIcon('heroicon-o-paper-clip')
|
||||
->falseIcon('heroicon-o-minus'),
|
||||
TextColumn::make('creator.name')
|
||||
->label('Created By')
|
||||
->sortable()
|
||||
->toggleable(),
|
||||
TextColumn::make('created_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
TextColumn::make('updated_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
TextColumn::make('deleted_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
])
|
||||
->filters([
|
||||
SelectFilter::make('severity')
|
||||
->options(DisciplinarySeverity::class),
|
||||
TrashedFilter::make(),
|
||||
])
|
||||
->recordActions([
|
||||
ViewAction::make(),
|
||||
EditAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
ExportExcelAction::bulk('exportSelected', \App\Exports\ReportsExport::class, 'disciplinary-reports.xlsx'),
|
||||
DeleteBulkAction::make(),
|
||||
ForceDeleteBulkAction::make(),
|
||||
RestoreBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\EmployeeDocuments;
|
||||
|
||||
use App\Filament\Resources\EmployeeDocuments\Pages\CreateEmployeeDocument;
|
||||
use App\Filament\Resources\EmployeeDocuments\Pages\EditEmployeeDocument;
|
||||
use App\Filament\Resources\EmployeeDocuments\Pages\ListEmployeeDocuments;
|
||||
use App\Filament\Resources\EmployeeDocuments\Pages\ViewEmployeeDocument;
|
||||
use App\Filament\Resources\EmployeeDocuments\Schemas\EmployeeDocumentForm;
|
||||
use App\Filament\Resources\EmployeeDocuments\Schemas\EmployeeDocumentInfolist;
|
||||
use App\Filament\Resources\EmployeeDocuments\Tables\EmployeeDocumentsTable;
|
||||
use App\Models\EmployeeDocument;
|
||||
use BackedEnum;
|
||||
use UnitEnum;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\SoftDeletingScope;
|
||||
|
||||
class EmployeeDocumentResource extends Resource
|
||||
{
|
||||
protected static ?string $model = EmployeeDocument::class;
|
||||
|
||||
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedDocument;
|
||||
|
||||
protected static string | UnitEnum | null $navigationGroup = 'Records';
|
||||
|
||||
protected static ?int $navigationSort = 5;
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'title';
|
||||
|
||||
protected static bool $isGloballySearchable = false;
|
||||
|
||||
public static function form(Schema $schema): Schema
|
||||
{
|
||||
return EmployeeDocumentForm::configure($schema);
|
||||
}
|
||||
|
||||
public static function infolist(Schema $schema): Schema
|
||||
{
|
||||
return EmployeeDocumentInfolist::configure($schema);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return EmployeeDocumentsTable::configure($table);
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ListEmployeeDocuments::route('/'),
|
||||
'create' => CreateEmployeeDocument::route('/create'),
|
||||
'view' => ViewEmployeeDocument::route('/{record}'),
|
||||
'edit' => EditEmployeeDocument::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
|
||||
public static function getRecordRouteBindingEloquentQuery(): Builder
|
||||
{
|
||||
return parent::getRecordRouteBindingEloquentQuery()
|
||||
->withoutGlobalScopes([
|
||||
SoftDeletingScope::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\EmployeeDocuments\Pages;
|
||||
|
||||
use App\Filament\Resources\EmployeeDocuments\EmployeeDocumentResource;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateEmployeeDocument extends CreateRecord
|
||||
{
|
||||
protected static string $resource = EmployeeDocumentResource::class;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\EmployeeDocuments\Pages;
|
||||
|
||||
use App\Filament\Resources\EmployeeDocuments\EmployeeDocumentResource;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\ForceDeleteAction;
|
||||
use Filament\Actions\RestoreAction;
|
||||
use Filament\Actions\ViewAction;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditEmployeeDocument extends EditRecord
|
||||
{
|
||||
protected static string $resource = EmployeeDocumentResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
ViewAction::make(),
|
||||
DeleteAction::make(),
|
||||
ForceDeleteAction::make(),
|
||||
RestoreAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\EmployeeDocuments\Pages;
|
||||
|
||||
use App\Filament\Resources\EmployeeDocuments\EmployeeDocumentResource;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListEmployeeDocuments extends ListRecords
|
||||
{
|
||||
protected static string $resource = EmployeeDocumentResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
CreateAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\EmployeeDocuments\Pages;
|
||||
|
||||
use App\Filament\Resources\EmployeeDocuments\EmployeeDocumentResource;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Resources\Pages\ViewRecord;
|
||||
|
||||
class ViewEmployeeDocument extends ViewRecord
|
||||
{
|
||||
protected static string $resource = EmployeeDocumentResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
EditAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\EmployeeDocuments\Schemas;
|
||||
|
||||
use App\Enums\DocumentType;
|
||||
use App\Filament\Support\HrForm;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class EmployeeDocumentForm
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
HrForm::employeeSelect(),
|
||||
Select::make('document_type')
|
||||
->options(DocumentType::class)
|
||||
->required()
|
||||
->native(false),
|
||||
TextInput::make('title')
|
||||
->required()
|
||||
->maxLength(255),
|
||||
HrForm::fileUpload('file_path')
|
||||
->label('Document')
|
||||
->required()
|
||||
->acceptedFileTypes(['application/pdf', 'image/*', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'])
|
||||
->maxSize(15360),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\EmployeeDocuments\Schemas;
|
||||
|
||||
use App\Models\EmployeeDocument;
|
||||
use Filament\Infolists\Components\TextEntry;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class EmployeeDocumentInfolist
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
TextEntry::make('employee.id')
|
||||
->label('Employee'),
|
||||
TextEntry::make('document_type')
|
||||
->badge(),
|
||||
TextEntry::make('title'),
|
||||
TextEntry::make('file_path'),
|
||||
TextEntry::make('uploaded_at')
|
||||
->dateTime(),
|
||||
TextEntry::make('created_at')
|
||||
->dateTime()
|
||||
->placeholder('-'),
|
||||
TextEntry::make('updated_at')
|
||||
->dateTime()
|
||||
->placeholder('-'),
|
||||
TextEntry::make('deleted_at')
|
||||
->dateTime()
|
||||
->visible(fn (EmployeeDocument $record): bool => $record->trashed()),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\EmployeeDocuments\Tables;
|
||||
|
||||
use App\Enums\DocumentType;
|
||||
use App\Models\EmployeeDocument;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ForceDeleteBulkAction;
|
||||
use Filament\Actions\RestoreBulkAction;
|
||||
use Filament\Actions\ViewAction;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use Filament\Tables\Filters\TrashedFilter;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class EmployeeDocumentsTable
|
||||
{
|
||||
public static function configure(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
TextColumn::make('employee.full_name')
|
||||
->label('Employee')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('document_type')
|
||||
->label('Type')
|
||||
->badge()
|
||||
->color(fn (DocumentType $state): string => $state->color())
|
||||
->formatStateUsing(fn (DocumentType $state): string => $state->label())
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('title')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('uploaded_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
TextColumn::make('created_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
TextColumn::make('updated_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
TextColumn::make('deleted_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
])
|
||||
->filters([
|
||||
SelectFilter::make('document_type')
|
||||
->label('Type')
|
||||
->options(DocumentType::class),
|
||||
TrashedFilter::make(),
|
||||
])
|
||||
->recordActions([
|
||||
Action::make('download')
|
||||
->label('Download')
|
||||
->icon('heroicon-o-arrow-down-tray')
|
||||
->visible(fn (EmployeeDocument $record): bool => filled($record->file_path))
|
||||
->action(function (EmployeeDocument $record) {
|
||||
$disk = Storage::disk(config('hr.file_uploads.disk'));
|
||||
|
||||
return response()->download(
|
||||
$disk->path($record->file_path),
|
||||
basename($record->file_path),
|
||||
);
|
||||
}),
|
||||
ViewAction::make(),
|
||||
EditAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
ForceDeleteBulkAction::make(),
|
||||
RestoreBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
120
app/Filament/Resources/Employees/EmployeeResource.php
Normal file
120
app/Filament/Resources/Employees/EmployeeResource.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\Employees;
|
||||
|
||||
use App\Filament\Resources\Employees\Pages\CreateEmployee;
|
||||
use App\Filament\Resources\Employees\Pages\EditEmployee;
|
||||
use App\Filament\Resources\Employees\Pages\ListEmployees;
|
||||
use App\Filament\Resources\Employees\Pages\ViewEmployee;
|
||||
use App\Filament\Resources\Employees\RelationManagers\BonusesRelationManager;
|
||||
use App\Filament\Resources\Employees\RelationManagers\DisciplinaryReportsRelationManager;
|
||||
use App\Filament\Resources\Employees\RelationManagers\DocumentsRelationManager;
|
||||
use App\Filament\Resources\Employees\RelationManagers\ExplanationsRelationManager;
|
||||
use App\Filament\Resources\Employees\RelationManagers\GiftsRelationManager;
|
||||
use App\Filament\Resources\Employees\RelationManagers\SickLeavesRelationManager;
|
||||
use App\Filament\Resources\Employees\RelationManagers\UnpaidLeavesRelationManager;
|
||||
use App\Filament\Resources\Employees\RelationManagers\VacationsRelationManager;
|
||||
use App\Filament\Resources\Employees\Schemas\EmployeeForm;
|
||||
use App\Filament\Resources\Employees\Schemas\EmployeeInfolist;
|
||||
use App\Filament\Resources\Employees\Tables\EmployeesTable;
|
||||
use App\Models\Employee;
|
||||
use BackedEnum;
|
||||
use UnitEnum;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletingScope;
|
||||
|
||||
class EmployeeResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Employee::class;
|
||||
|
||||
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedUsers;
|
||||
|
||||
protected static string | UnitEnum | null $navigationGroup = 'Employees';
|
||||
|
||||
protected static ?int $navigationSort = 1;
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'full_name';
|
||||
|
||||
protected static bool $isGloballySearchable = true;
|
||||
|
||||
public static function form(Schema $schema): Schema
|
||||
{
|
||||
return EmployeeForm::configure($schema);
|
||||
}
|
||||
|
||||
public static function infolist(Schema $schema): Schema
|
||||
{
|
||||
return EmployeeInfolist::configure($schema);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return EmployeesTable::configure($table);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string>
|
||||
*/
|
||||
public static function getGloballySearchableAttributes(): array
|
||||
{
|
||||
return [
|
||||
'employee_number',
|
||||
'full_name',
|
||||
'phone',
|
||||
'department.name',
|
||||
'position.name',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public static function getGlobalSearchResultDetails(Model $record): array
|
||||
{
|
||||
/** @var Employee $record */
|
||||
return [
|
||||
'Employee #' => $record->employee_number,
|
||||
'Department' => $record->department?->name ?? '—',
|
||||
'Position' => $record->position?->name ?? '—',
|
||||
];
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
VacationsRelationManager::class,
|
||||
SickLeavesRelationManager::class,
|
||||
UnpaidLeavesRelationManager::class,
|
||||
DisciplinaryReportsRelationManager::class,
|
||||
ExplanationsRelationManager::class,
|
||||
BonusesRelationManager::class,
|
||||
GiftsRelationManager::class,
|
||||
DocumentsRelationManager::class,
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ListEmployees::route('/'),
|
||||
'create' => CreateEmployee::route('/create'),
|
||||
'view' => ViewEmployee::route('/{record}'),
|
||||
'edit' => EditEmployee::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
|
||||
public static function getRecordRouteBindingEloquentQuery(): Builder
|
||||
{
|
||||
return parent::getRecordRouteBindingEloquentQuery()
|
||||
->withoutGlobalScopes([
|
||||
SoftDeletingScope::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
11
app/Filament/Resources/Employees/Pages/CreateEmployee.php
Normal file
11
app/Filament/Resources/Employees/Pages/CreateEmployee.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Employees\Pages;
|
||||
|
||||
use App\Filament\Resources\Employees\EmployeeResource;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateEmployee extends CreateRecord
|
||||
{
|
||||
protected static string $resource = EmployeeResource::class;
|
||||
}
|
||||
25
app/Filament/Resources/Employees/Pages/EditEmployee.php
Normal file
25
app/Filament/Resources/Employees/Pages/EditEmployee.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Employees\Pages;
|
||||
|
||||
use App\Filament\Resources\Employees\EmployeeResource;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\ForceDeleteAction;
|
||||
use Filament\Actions\RestoreAction;
|
||||
use Filament\Actions\ViewAction;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditEmployee extends EditRecord
|
||||
{
|
||||
protected static string $resource = EmployeeResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
ViewAction::make(),
|
||||
DeleteAction::make(),
|
||||
ForceDeleteAction::make(),
|
||||
RestoreAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
26
app/Filament/Resources/Employees/Pages/ListEmployees.php
Normal file
26
app/Filament/Resources/Employees/Pages/ListEmployees.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\Employees\Pages;
|
||||
|
||||
use App\Exports\EmployeesExport;
|
||||
use App\Filament\Resources\Employees\EmployeeResource;
|
||||
use App\Filament\Support\ExportExcelAction;
|
||||
use App\Filament\Support\ExportPdfAction;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListEmployees extends ListRecords
|
||||
{
|
||||
protected static string $resource = EmployeeResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
ExportExcelAction::make('export', EmployeesExport::class, 'employees.xlsx'),
|
||||
ExportPdfAction::employeeList(),
|
||||
CreateAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
47
app/Filament/Resources/Employees/Pages/ViewEmployee.php
Normal file
47
app/Filament/Resources/Employees/Pages/ViewEmployee.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\Employees\Pages;
|
||||
|
||||
use App\Filament\Resources\Employees\EmployeeResource;
|
||||
use App\Filament\Resources\Employees\Widgets\EmployeeStatsWidget;
|
||||
use App\Filament\Support\ExportPdfAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Resources\Pages\ViewRecord;
|
||||
|
||||
class ViewEmployee extends ViewRecord
|
||||
{
|
||||
protected static string $resource = EmployeeResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
ExportPdfAction::employeeProfile(),
|
||||
ExportPdfAction::employeeLeaveSummary(),
|
||||
EditAction::make(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<class-string>
|
||||
*/
|
||||
protected function getHeaderWidgets(): array
|
||||
{
|
||||
return [
|
||||
EmployeeStatsWidget::class,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int | array<string, ?int>
|
||||
*/
|
||||
public function getHeaderWidgetsColumns(): int | array
|
||||
{
|
||||
return [
|
||||
'default' => 1,
|
||||
'sm' => 2,
|
||||
'xl' => 4,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\Employees\RelationManagers;
|
||||
|
||||
use App\Enums\BonusType;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ForceDeleteBulkAction;
|
||||
use Filament\Actions\RestoreBulkAction;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Components\Textarea;
|
||||
use Filament\Resources\RelationManagers\RelationManager;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use Filament\Tables\Filters\TrashedFilter;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class BonusesRelationManager extends RelationManager
|
||||
{
|
||||
protected static string $relationship = 'bonuses';
|
||||
|
||||
protected static ?string $title = 'Bonuses';
|
||||
|
||||
public function form(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
DatePicker::make('bonus_date')
|
||||
->required()
|
||||
->default(now()),
|
||||
Select::make('bonus_type')
|
||||
->options(BonusType::class)
|
||||
->required()
|
||||
->native(false),
|
||||
TextInput::make('amount')
|
||||
->required()
|
||||
->numeric()
|
||||
->prefix('TMT')
|
||||
->minValue(0)
|
||||
->step(0.01),
|
||||
Textarea::make('reason')
|
||||
->rows(3)
|
||||
->columnSpanFull(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->recordTitleAttribute('bonus_date')
|
||||
->columns([
|
||||
TextColumn::make('bonus_date')
|
||||
->date()
|
||||
->sortable(),
|
||||
TextColumn::make('bonus_type')
|
||||
->label('Type')
|
||||
->badge()
|
||||
->color(fn (BonusType $state): string => $state->color())
|
||||
->formatStateUsing(fn (BonusType $state): string => $state->label())
|
||||
->sortable(),
|
||||
TextColumn::make('amount')
|
||||
->money('TMT')
|
||||
->sortable(),
|
||||
TextColumn::make('reason')
|
||||
->limit(40)
|
||||
->toggleable(),
|
||||
])
|
||||
->filters([
|
||||
SelectFilter::make('bonus_type')
|
||||
->label('Type')
|
||||
->options(BonusType::class),
|
||||
TrashedFilter::make(),
|
||||
])
|
||||
->headerActions([
|
||||
CreateAction::make(),
|
||||
])
|
||||
->recordActions([
|
||||
EditAction::make(),
|
||||
DeleteAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
ForceDeleteBulkAction::make(),
|
||||
RestoreBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\Employees\RelationManagers;
|
||||
|
||||
use App\Enums\DisciplinarySeverity;
|
||||
use App\Filament\Support\HrForm;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ForceDeleteBulkAction;
|
||||
use Filament\Actions\RestoreBulkAction;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Components\Textarea;
|
||||
use Filament\Resources\RelationManagers\RelationManager;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Tables\Columns\IconColumn;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use Filament\Tables\Filters\TrashedFilter;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class DisciplinaryReportsRelationManager extends RelationManager
|
||||
{
|
||||
protected static string $relationship = 'disciplinaryReports';
|
||||
|
||||
protected static ?string $title = 'Disciplinary Reports';
|
||||
|
||||
public function form(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
DatePicker::make('report_date')
|
||||
->required()
|
||||
->default(now()),
|
||||
TextInput::make('title')
|
||||
->required()
|
||||
->maxLength(255),
|
||||
Textarea::make('description')
|
||||
->required()
|
||||
->rows(4)
|
||||
->columnSpanFull(),
|
||||
Select::make('severity')
|
||||
->options(DisciplinarySeverity::class)
|
||||
->required()
|
||||
->native(false),
|
||||
HrForm::fileUpload('attachment_path')
|
||||
->label('Attachment')
|
||||
->acceptedFileTypes(['application/pdf', 'image/*'])
|
||||
->maxSize(10240),
|
||||
]);
|
||||
}
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->recordTitleAttribute('title')
|
||||
->columns([
|
||||
TextColumn::make('report_date')
|
||||
->date()
|
||||
->sortable(),
|
||||
TextColumn::make('title')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('severity')
|
||||
->badge()
|
||||
->color(fn (DisciplinarySeverity $state): string => $state->color())
|
||||
->formatStateUsing(fn (DisciplinarySeverity $state): string => $state->label())
|
||||
->sortable(),
|
||||
IconColumn::make('attachment_path')
|
||||
->label('Attachment')
|
||||
->boolean()
|
||||
->trueIcon('heroicon-o-paper-clip')
|
||||
->falseIcon('heroicon-o-minus'),
|
||||
TextColumn::make('creator.name')
|
||||
->label('Created By')
|
||||
->toggleable(),
|
||||
])
|
||||
->filters([
|
||||
SelectFilter::make('severity')
|
||||
->options(DisciplinarySeverity::class),
|
||||
TrashedFilter::make(),
|
||||
])
|
||||
->headerActions([
|
||||
CreateAction::make(),
|
||||
])
|
||||
->recordActions([
|
||||
EditAction::make(),
|
||||
DeleteAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
ForceDeleteBulkAction::make(),
|
||||
RestoreBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\Employees\RelationManagers;
|
||||
|
||||
use App\Enums\DocumentType;
|
||||
use App\Filament\Support\HrForm;
|
||||
use App\Models\EmployeeDocument;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ForceDeleteBulkAction;
|
||||
use Filament\Actions\RestoreBulkAction;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Resources\RelationManagers\RelationManager;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use Filament\Tables\Filters\TrashedFilter;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class DocumentsRelationManager extends RelationManager
|
||||
{
|
||||
protected static string $relationship = 'documents';
|
||||
|
||||
protected static ?string $title = 'Employee Documents';
|
||||
|
||||
public function form(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
Select::make('document_type')
|
||||
->options(DocumentType::class)
|
||||
->required()
|
||||
->native(false),
|
||||
TextInput::make('title')
|
||||
->required()
|
||||
->maxLength(255),
|
||||
HrForm::fileUpload('file_path')
|
||||
->label('Document')
|
||||
->required()
|
||||
->acceptedFileTypes(['application/pdf', 'image/*', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'])
|
||||
->maxSize(15360),
|
||||
]);
|
||||
}
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->recordTitleAttribute('title')
|
||||
->columns([
|
||||
TextColumn::make('document_type')
|
||||
->label('Type')
|
||||
->badge()
|
||||
->color(fn (DocumentType $state): string => $state->color())
|
||||
->formatStateUsing(fn (DocumentType $state): string => $state->label())
|
||||
->sortable(),
|
||||
TextColumn::make('title')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('uploaded_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
])
|
||||
->filters([
|
||||
SelectFilter::make('document_type')
|
||||
->label('Type')
|
||||
->options(DocumentType::class),
|
||||
TrashedFilter::make(),
|
||||
])
|
||||
->headerActions([
|
||||
CreateAction::make(),
|
||||
])
|
||||
->recordActions([
|
||||
Action::make('download')
|
||||
->label('Download')
|
||||
->icon('heroicon-o-arrow-down-tray')
|
||||
->visible(fn (EmployeeDocument $record): bool => filled($record->file_path))
|
||||
->action(function (EmployeeDocument $record) {
|
||||
$disk = Storage::disk(config('hr.file_uploads.disk'));
|
||||
|
||||
return response()->download(
|
||||
$disk->path($record->file_path),
|
||||
basename($record->file_path),
|
||||
);
|
||||
}),
|
||||
EditAction::make(),
|
||||
DeleteAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
ForceDeleteBulkAction::make(),
|
||||
RestoreBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\Employees\RelationManagers;
|
||||
|
||||
use App\Filament\Support\HrForm;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ForceDeleteBulkAction;
|
||||
use Filament\Actions\RestoreBulkAction;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Components\Textarea;
|
||||
use Filament\Resources\RelationManagers\RelationManager;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Tables\Columns\IconColumn;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\TrashedFilter;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class ExplanationsRelationManager extends RelationManager
|
||||
{
|
||||
protected static string $relationship = 'explanations';
|
||||
|
||||
protected static ?string $title = 'Explanations';
|
||||
|
||||
public function form(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
DatePicker::make('explanation_date')
|
||||
->required()
|
||||
->default(now()),
|
||||
TextInput::make('reason')
|
||||
->required()
|
||||
->maxLength(255),
|
||||
Textarea::make('description')
|
||||
->required()
|
||||
->rows(4)
|
||||
->columnSpanFull(),
|
||||
HrForm::fileUpload('attachment_path')
|
||||
->label('Attachment')
|
||||
->acceptedFileTypes(['application/pdf', 'image/*'])
|
||||
->maxSize(10240),
|
||||
]);
|
||||
}
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->recordTitleAttribute('reason')
|
||||
->columns([
|
||||
TextColumn::make('explanation_date')
|
||||
->date()
|
||||
->sortable(),
|
||||
TextColumn::make('reason')
|
||||
->searchable()
|
||||
->limit(40),
|
||||
TextColumn::make('description')
|
||||
->limit(50)
|
||||
->toggleable(),
|
||||
IconColumn::make('attachment_path')
|
||||
->label('Attachment')
|
||||
->boolean()
|
||||
->trueIcon('heroicon-o-paper-clip')
|
||||
->falseIcon('heroicon-o-minus'),
|
||||
])
|
||||
->filters([
|
||||
TrashedFilter::make(),
|
||||
])
|
||||
->headerActions([
|
||||
CreateAction::make(),
|
||||
])
|
||||
->recordActions([
|
||||
EditAction::make(),
|
||||
DeleteAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
ForceDeleteBulkAction::make(),
|
||||
RestoreBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\Employees\RelationManagers;
|
||||
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ForceDeleteBulkAction;
|
||||
use Filament\Actions\RestoreBulkAction;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Components\Textarea;
|
||||
use Filament\Resources\RelationManagers\RelationManager;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\TrashedFilter;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class GiftsRelationManager extends RelationManager
|
||||
{
|
||||
protected static string $relationship = 'gifts';
|
||||
|
||||
protected static ?string $title = 'Gifts';
|
||||
|
||||
public function form(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
DatePicker::make('gift_date')
|
||||
->required()
|
||||
->default(now()),
|
||||
TextInput::make('gift_name')
|
||||
->label('Gift Name')
|
||||
->required()
|
||||
->maxLength(255),
|
||||
TextInput::make('value')
|
||||
->required()
|
||||
->numeric()
|
||||
->prefix('TMT')
|
||||
->minValue(0)
|
||||
->step(0.01)
|
||||
->default(0),
|
||||
Textarea::make('reason')
|
||||
->rows(3)
|
||||
->columnSpanFull(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->recordTitleAttribute('gift_name')
|
||||
->columns([
|
||||
TextColumn::make('gift_date')
|
||||
->date()
|
||||
->sortable(),
|
||||
TextColumn::make('gift_name')
|
||||
->label('Gift')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('value')
|
||||
->money('TMT')
|
||||
->sortable(),
|
||||
TextColumn::make('reason')
|
||||
->limit(40)
|
||||
->toggleable(),
|
||||
])
|
||||
->filters([
|
||||
TrashedFilter::make(),
|
||||
])
|
||||
->headerActions([
|
||||
CreateAction::make(),
|
||||
])
|
||||
->recordActions([
|
||||
EditAction::make(),
|
||||
DeleteAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
ForceDeleteBulkAction::make(),
|
||||
RestoreBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\Employees\RelationManagers;
|
||||
|
||||
use App\Filament\Support\HrForm;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ForceDeleteBulkAction;
|
||||
use Filament\Actions\RestoreBulkAction;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Components\Textarea;
|
||||
use Filament\Resources\RelationManagers\RelationManager;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Tables\Columns\IconColumn;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\TrashedFilter;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class SickLeavesRelationManager extends RelationManager
|
||||
{
|
||||
protected static string $relationship = 'sickLeaves';
|
||||
|
||||
protected static ?string $title = 'Sick Leaves';
|
||||
|
||||
public function form(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
HrForm::leaveDatePicker('start_date', 'Start Date'),
|
||||
HrForm::leaveDatePicker('end_date', 'End Date'),
|
||||
HrForm::leaveDaysDisplay(),
|
||||
TextInput::make('medical_institution')
|
||||
->maxLength(255),
|
||||
Textarea::make('reason')
|
||||
->rows(3)
|
||||
->columnSpanFull(),
|
||||
HrForm::fileUpload('document_path')
|
||||
->label('Medical Document')
|
||||
->acceptedFileTypes(['application/pdf', 'image/*'])
|
||||
->maxSize(10240),
|
||||
]);
|
||||
}
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->recordTitleAttribute('start_date')
|
||||
->columns([
|
||||
TextColumn::make('start_date')
|
||||
->date()
|
||||
->sortable(),
|
||||
TextColumn::make('end_date')
|
||||
->date()
|
||||
->sortable(),
|
||||
TextColumn::make('days')
|
||||
->numeric()
|
||||
->sortable(),
|
||||
TextColumn::make('medical_institution')
|
||||
->searchable()
|
||||
->toggleable(),
|
||||
IconColumn::make('document_path')
|
||||
->label('Document')
|
||||
->boolean()
|
||||
->trueIcon('heroicon-o-document-check')
|
||||
->falseIcon('heroicon-o-document'),
|
||||
])
|
||||
->filters([
|
||||
TrashedFilter::make(),
|
||||
])
|
||||
->headerActions([
|
||||
CreateAction::make(),
|
||||
])
|
||||
->recordActions([
|
||||
EditAction::make(),
|
||||
DeleteAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
ForceDeleteBulkAction::make(),
|
||||
RestoreBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\Employees\RelationManagers;
|
||||
|
||||
use App\Enums\ApprovalStatus;
|
||||
use App\Filament\Support\HrForm;
|
||||
use App\Models\UnpaidLeave;
|
||||
use App\Services\Leave\UnpaidLeaveService;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ForceDeleteBulkAction;
|
||||
use Filament\Actions\RestoreBulkAction;
|
||||
use Filament\Forms\Components\Textarea;
|
||||
use Filament\Resources\RelationManagers\RelationManager;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use Filament\Tables\Filters\TrashedFilter;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class UnpaidLeavesRelationManager extends RelationManager
|
||||
{
|
||||
protected static string $relationship = 'unpaidLeaves';
|
||||
|
||||
protected static ?string $title = 'Unpaid Leaves';
|
||||
|
||||
public function form(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
HrForm::leaveDatePicker('start_date', 'Start Date'),
|
||||
HrForm::leaveDatePicker('end_date', 'End Date'),
|
||||
HrForm::leaveDaysDisplay(),
|
||||
Textarea::make('reason')
|
||||
->rows(3)
|
||||
->columnSpanFull(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->recordTitleAttribute('start_date')
|
||||
->columns([
|
||||
TextColumn::make('start_date')
|
||||
->date()
|
||||
->sortable(),
|
||||
TextColumn::make('end_date')
|
||||
->date()
|
||||
->sortable(),
|
||||
TextColumn::make('days')
|
||||
->numeric()
|
||||
->sortable(),
|
||||
TextColumn::make('status')
|
||||
->badge()
|
||||
->color(fn (ApprovalStatus $state): string => $state->color())
|
||||
->formatStateUsing(fn (ApprovalStatus $state): string => $state->label())
|
||||
->sortable(),
|
||||
TextColumn::make('approver.name')
|
||||
->label('Approved By')
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
])
|
||||
->filters([
|
||||
SelectFilter::make('status')
|
||||
->options(ApprovalStatus::class),
|
||||
TrashedFilter::make(),
|
||||
])
|
||||
->headerActions([
|
||||
CreateAction::make(),
|
||||
])
|
||||
->recordActions([
|
||||
Action::make('approve')
|
||||
->label('Approve')
|
||||
->icon('heroicon-o-check-badge')
|
||||
->color('success')
|
||||
->requiresConfirmation()
|
||||
->visible(fn (UnpaidLeave $record): bool => $record->status === ApprovalStatus::Pending)
|
||||
->action(function (UnpaidLeave $record, UnpaidLeaveService $unpaidLeaveService): void {
|
||||
$unpaidLeaveService->approve($record, Auth::user());
|
||||
}),
|
||||
Action::make('reject')
|
||||
->label('Reject')
|
||||
->icon('heroicon-o-x-mark')
|
||||
->color('danger')
|
||||
->requiresConfirmation()
|
||||
->visible(fn (UnpaidLeave $record): bool => $record->status === ApprovalStatus::Pending)
|
||||
->action(function (UnpaidLeave $record, UnpaidLeaveService $unpaidLeaveService): void {
|
||||
$unpaidLeaveService->reject($record, Auth::user());
|
||||
}),
|
||||
EditAction::make(),
|
||||
DeleteAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
ForceDeleteBulkAction::make(),
|
||||
RestoreBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\Employees\RelationManagers;
|
||||
|
||||
use App\Enums\ApprovalStatus;
|
||||
use App\Enums\VacationType;
|
||||
use App\Filament\Support\HrForm;
|
||||
use App\Models\Vacation;
|
||||
use App\Services\Vacation\VacationService;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ForceDeleteBulkAction;
|
||||
use Filament\Actions\RestoreBulkAction;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\Textarea;
|
||||
use Filament\Resources\RelationManagers\RelationManager;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use Filament\Tables\Filters\TrashedFilter;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class VacationsRelationManager extends RelationManager
|
||||
{
|
||||
protected static string $relationship = 'vacations';
|
||||
|
||||
protected static ?string $title = 'Vacations';
|
||||
|
||||
public function form(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
Select::make('type')
|
||||
->options(VacationType::class)
|
||||
->required()
|
||||
->native(false),
|
||||
HrForm::leaveDatePicker('start_date', 'Start Date'),
|
||||
HrForm::leaveDatePicker('end_date', 'End Date'),
|
||||
DatePicker::make('return_date')
|
||||
->label('Return Date'),
|
||||
HrForm::leaveDaysDisplay(),
|
||||
Textarea::make('reason')
|
||||
->rows(3)
|
||||
->columnSpanFull(),
|
||||
HrForm::fileUpload('attachment_path')
|
||||
->label('Attachment')
|
||||
->acceptedFileTypes(['application/pdf', 'image/*'])
|
||||
->maxSize(10240),
|
||||
]);
|
||||
}
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->recordTitleAttribute('start_date')
|
||||
->columns([
|
||||
TextColumn::make('type')
|
||||
->badge()
|
||||
->color(fn (VacationType $state): string => $state->color())
|
||||
->formatStateUsing(fn (VacationType $state): string => $state->label())
|
||||
->sortable(),
|
||||
TextColumn::make('start_date')
|
||||
->date()
|
||||
->sortable(),
|
||||
TextColumn::make('end_date')
|
||||
->date()
|
||||
->sortable(),
|
||||
TextColumn::make('days')
|
||||
->numeric()
|
||||
->sortable(),
|
||||
TextColumn::make('status')
|
||||
->badge()
|
||||
->color(fn (ApprovalStatus $state): string => $state->color())
|
||||
->formatStateUsing(fn (ApprovalStatus $state): string => $state->label())
|
||||
->sortable(),
|
||||
TextColumn::make('approver.name')
|
||||
->label('Approved By')
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
])
|
||||
->filters([
|
||||
SelectFilter::make('status')
|
||||
->options(ApprovalStatus::class),
|
||||
SelectFilter::make('type')
|
||||
->options(VacationType::class),
|
||||
TrashedFilter::make(),
|
||||
])
|
||||
->headerActions([
|
||||
CreateAction::make(),
|
||||
])
|
||||
->recordActions([
|
||||
Action::make('approve')
|
||||
->label('Approve')
|
||||
->icon('heroicon-o-check-badge')
|
||||
->color('success')
|
||||
->requiresConfirmation()
|
||||
->visible(fn (Vacation $record): bool => $record->status === ApprovalStatus::Pending)
|
||||
->action(function (Vacation $record, VacationService $vacationService): void {
|
||||
$vacationService->approve($record, Auth::user());
|
||||
}),
|
||||
Action::make('reject')
|
||||
->label('Reject')
|
||||
->icon('heroicon-o-x-mark')
|
||||
->color('danger')
|
||||
->requiresConfirmation()
|
||||
->visible(fn (Vacation $record): bool => $record->status === ApprovalStatus::Pending)
|
||||
->action(function (Vacation $record, VacationService $vacationService): void {
|
||||
$vacationService->reject($record, Auth::user());
|
||||
}),
|
||||
EditAction::make(),
|
||||
DeleteAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
ForceDeleteBulkAction::make(),
|
||||
RestoreBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
90
app/Filament/Resources/Employees/Schemas/EmployeeForm.php
Normal file
90
app/Filament/Resources/Employees/Schemas/EmployeeForm.php
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Employees\Schemas;
|
||||
|
||||
use App\Enums\EmploymentStatus;
|
||||
use App\Enums\Gender;
|
||||
use App\Filament\Support\HrForm;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Components\Textarea;
|
||||
use Filament\Schemas\Components\Tabs;
|
||||
use Filament\Schemas\Components\Tabs\Tab;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class EmployeeForm
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
Tabs::make('Employee')
|
||||
->tabs([
|
||||
Tab::make('Personal')
|
||||
->schema([
|
||||
HrForm::fileUpload('profile_photo_path')
|
||||
->label('Photo')
|
||||
->image()
|
||||
->avatar()
|
||||
->imageEditor(),
|
||||
TextInput::make('employee_number')
|
||||
->required()
|
||||
->maxLength(50)
|
||||
->unique(ignoreRecord: true),
|
||||
TextInput::make('full_name')
|
||||
->required()
|
||||
->maxLength(255),
|
||||
TextInput::make('national_id')
|
||||
->label('National ID')
|
||||
->maxLength(50),
|
||||
Select::make('gender')
|
||||
->options(Gender::class)
|
||||
->required()
|
||||
->native(false),
|
||||
DatePicker::make('birth_date')
|
||||
->required(),
|
||||
TextInput::make('phone')
|
||||
->tel()
|
||||
->default(config('hr.default_phone'))
|
||||
->required(),
|
||||
Textarea::make('address')
|
||||
->rows(3)
|
||||
->columnSpanFull(),
|
||||
])
|
||||
->columns(2),
|
||||
Tab::make('Employment')
|
||||
->schema([
|
||||
Select::make('department_id')
|
||||
->relationship('department', 'name')
|
||||
->searchable()
|
||||
->preload()
|
||||
->required(),
|
||||
Select::make('position_id')
|
||||
->relationship('position', 'name')
|
||||
->searchable()
|
||||
->preload()
|
||||
->required(),
|
||||
Select::make('shift_id')
|
||||
->relationship('shift', 'name')
|
||||
->searchable()
|
||||
->preload()
|
||||
->required(),
|
||||
Select::make('employment_status')
|
||||
->options(EmploymentStatus::class)
|
||||
->default(EmploymentStatus::Active)
|
||||
->required()
|
||||
->native(false),
|
||||
DatePicker::make('hire_date')
|
||||
->required(),
|
||||
DatePicker::make('termination_date'),
|
||||
Textarea::make('notes')
|
||||
->rows(4)
|
||||
->columnSpanFull(),
|
||||
])
|
||||
->columns(2),
|
||||
])
|
||||
->columnSpanFull(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
204
app/Filament/Resources/Employees/Schemas/EmployeeInfolist.php
Normal file
204
app/Filament/Resources/Employees/Schemas/EmployeeInfolist.php
Normal file
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\Employees\Schemas;
|
||||
|
||||
use App\Enums\EmploymentStatus;
|
||||
use App\Enums\Gender;
|
||||
use App\Models\Employee;
|
||||
use App\Models\Vacation;
|
||||
use App\Services\Employee\EmployeeStatisticsService;
|
||||
use Filament\Infolists\Components\ImageEntry;
|
||||
use Filament\Infolists\Components\TextEntry;
|
||||
use Filament\Schemas\Components\Section;
|
||||
use Filament\Schemas\Components\Tabs;
|
||||
use Filament\Schemas\Components\Tabs\Tab;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class EmployeeInfolist
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
Tabs::make('Employee Details')
|
||||
->tabs([
|
||||
Tab::make('Overview')
|
||||
->schema([
|
||||
Section::make('Profile')
|
||||
->schema([
|
||||
ImageEntry::make('profile_photo_path')
|
||||
->label('Photo')
|
||||
->disk(config('hr.file_uploads.disk'))
|
||||
->visibility('private')
|
||||
->circular()
|
||||
->height(120)
|
||||
->placeholder('—')
|
||||
->columnSpanFull(),
|
||||
TextEntry::make('employee_number')
|
||||
->label('Employee #'),
|
||||
TextEntry::make('full_name'),
|
||||
TextEntry::make('national_id')
|
||||
->label('National ID')
|
||||
->placeholder('—'),
|
||||
TextEntry::make('gender')
|
||||
->badge()
|
||||
->color(fn (Gender $state): string => $state->color())
|
||||
->formatStateUsing(fn (Gender $state): string => $state->label()),
|
||||
TextEntry::make('birth_date')
|
||||
->date(),
|
||||
TextEntry::make('phone'),
|
||||
TextEntry::make('address')
|
||||
->placeholder('—')
|
||||
->columnSpanFull(),
|
||||
])
|
||||
->columns(2),
|
||||
Section::make('Organization')
|
||||
->schema([
|
||||
TextEntry::make('department.name')
|
||||
->label('Department')
|
||||
->badge()
|
||||
->color('info'),
|
||||
TextEntry::make('position.name')
|
||||
->label('Position')
|
||||
->badge()
|
||||
->color('primary'),
|
||||
TextEntry::make('shift.name')
|
||||
->label('Shift')
|
||||
->badge()
|
||||
->color('gray'),
|
||||
TextEntry::make('employment_status')
|
||||
->badge()
|
||||
->color(fn (EmploymentStatus $state): string => $state->color())
|
||||
->formatStateUsing(fn (EmploymentStatus $state): string => $state->label())
|
||||
->icon(fn (EmploymentStatus $state): string => $state->icon()),
|
||||
])
|
||||
->columns(2),
|
||||
Section::make('Employment Timeline')
|
||||
->schema([
|
||||
TextEntry::make('hire_date')
|
||||
->label('Hire Date')
|
||||
->date()
|
||||
->icon('heroicon-o-calendar'),
|
||||
TextEntry::make('termination_date')
|
||||
->label('Termination Date')
|
||||
->date()
|
||||
->placeholder('—')
|
||||
->icon('heroicon-o-calendar-days'),
|
||||
TextEntry::make('tenure')
|
||||
->label('Tenure')
|
||||
->state(fn (Employee $record): string => $record->hire_date
|
||||
? $record->hire_date->diffForHumans(now(), true)
|
||||
: '—'),
|
||||
TextEntry::make('notes')
|
||||
->placeholder('—')
|
||||
->columnSpanFull(),
|
||||
])
|
||||
->columns(2),
|
||||
]),
|
||||
Tab::make('Statistics')
|
||||
->schema([
|
||||
Section::make('Leave & Attendance')
|
||||
->schema([
|
||||
TextEntry::make('stats_vacation_taken')
|
||||
->label('Vacation Taken (days)')
|
||||
->state(fn (Employee $record): int => app(EmployeeStatisticsService::class)->summary($record)->vacationTaken)
|
||||
->numeric()
|
||||
->icon('heroicon-o-sun'),
|
||||
TextEntry::make('stats_vacation_remaining')
|
||||
->label('Vacation Remaining (days)')
|
||||
->state(fn (Employee $record): int => app(EmployeeStatisticsService::class)->summary($record)->vacationRemaining)
|
||||
->numeric()
|
||||
->color('success')
|
||||
->icon('heroicon-o-calendar'),
|
||||
TextEntry::make('stats_sick_leave_count')
|
||||
->label('Sick Leave Records')
|
||||
->state(fn (Employee $record): int => app(EmployeeStatisticsService::class)->summary($record)->sickLeaveCount)
|
||||
->numeric()
|
||||
->icon('heroicon-o-heart'),
|
||||
])
|
||||
->columns(3),
|
||||
Section::make('HR Records')
|
||||
->schema([
|
||||
TextEntry::make('stats_reports_count')
|
||||
->label('Disciplinary Reports')
|
||||
->state(fn (Employee $record): int => app(EmployeeStatisticsService::class)->summary($record)->reportsCount)
|
||||
->numeric()
|
||||
->icon('heroicon-o-exclamation-triangle'),
|
||||
TextEntry::make('stats_bonuses_total')
|
||||
->label('Total Bonuses')
|
||||
->state(fn (Employee $record): float => app(EmployeeStatisticsService::class)->summary($record)->bonusesTotal)
|
||||
->money('TMT')
|
||||
->icon('heroicon-o-banknotes'),
|
||||
TextEntry::make('stats_gifts_count')
|
||||
->label('Gifts Received')
|
||||
->state(fn (Employee $record): int => app(EmployeeStatisticsService::class)->summary($record)->giftsCount)
|
||||
->numeric()
|
||||
->icon('heroicon-o-gift'),
|
||||
])
|
||||
->columns(3),
|
||||
]),
|
||||
Tab::make('Leave Summary')
|
||||
->schema([
|
||||
Section::make('Annual Leave Balance')
|
||||
->schema([
|
||||
TextEntry::make('leave_balance_taken')
|
||||
->label('Days Taken')
|
||||
->state(fn (Employee $record): int => app(EmployeeStatisticsService::class)->summary($record)->vacationTaken)
|
||||
->suffix(' days'),
|
||||
TextEntry::make('leave_balance_remaining')
|
||||
->label('Days Remaining')
|
||||
->state(fn (Employee $record): int => app(EmployeeStatisticsService::class)->summary($record)->vacationRemaining)
|
||||
->suffix(' days')
|
||||
->color('success'),
|
||||
TextEntry::make('leave_balance_total')
|
||||
->label('Annual Allowance')
|
||||
->state(fn (): int => (int) config('hr.annual_leave_days'))
|
||||
->suffix(' days'),
|
||||
])
|
||||
->columns(3),
|
||||
Section::make('Upcoming Approved Leave')
|
||||
->schema([
|
||||
TextEntry::make('upcoming_leave')
|
||||
->label('Scheduled Vacations')
|
||||
->state(function (Employee $record): string {
|
||||
$upcoming = app(EmployeeStatisticsService::class)
|
||||
->summary($record)
|
||||
->upcomingLeave;
|
||||
|
||||
if ($upcoming->isEmpty()) {
|
||||
return 'No upcoming approved leave';
|
||||
}
|
||||
|
||||
return $upcoming
|
||||
->map(fn (Vacation $vacation): string => sprintf(
|
||||
'%s: %s – %s (%d days)',
|
||||
$vacation->type->label(),
|
||||
$vacation->start_date->format('M j, Y'),
|
||||
$vacation->end_date->format('M j, Y'),
|
||||
$vacation->days,
|
||||
))
|
||||
->implode("\n");
|
||||
})
|
||||
->listWithLineBreaks()
|
||||
->columnSpanFull(),
|
||||
]),
|
||||
Section::make('Other Leave Types')
|
||||
->schema([
|
||||
TextEntry::make('unpaid_leaves_count')
|
||||
->label('Unpaid Leave Records')
|
||||
->state(fn (Employee $record): int => $record->unpaidLeaves()->count())
|
||||
->numeric(),
|
||||
TextEntry::make('explanations_count')
|
||||
->label('Explanations')
|
||||
->state(fn (Employee $record): int => $record->explanations()->count())
|
||||
->numeric(),
|
||||
])
|
||||
->columns(2),
|
||||
]),
|
||||
])
|
||||
->columnSpanFull(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
146
app/Filament/Resources/Employees/Tables/EmployeesTable.php
Normal file
146
app/Filament/Resources/Employees/Tables/EmployeesTable.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Employees\Tables;
|
||||
|
||||
use App\Enums\EmploymentStatus;
|
||||
use App\Enums\Gender;
|
||||
use App\Models\Department;
|
||||
use App\Models\Employee;
|
||||
use App\Filament\Support\ExportExcelAction;
|
||||
use Filament\Actions\BulkAction;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ForceDeleteBulkAction;
|
||||
use Filament\Actions\RestoreBulkAction;
|
||||
use Filament\Actions\ViewAction;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use Filament\Tables\Filters\TrashedFilter;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
class EmployeesTable
|
||||
{
|
||||
public static function configure(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
TextColumn::make('employee_number')
|
||||
->label('Number')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('full_name')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('national_id')
|
||||
->label('National ID')
|
||||
->searchable()
|
||||
->toggleable(),
|
||||
TextColumn::make('gender')
|
||||
->badge()
|
||||
->color(fn (Gender $state): string => $state->color())
|
||||
->formatStateUsing(fn (Gender $state): string => $state->label())
|
||||
->searchable(),
|
||||
TextColumn::make('phone')
|
||||
->searchable()
|
||||
->toggleable(),
|
||||
TextColumn::make('department.name')
|
||||
->label('Department')
|
||||
->badge()
|
||||
->color('info')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('position.name')
|
||||
->label('Position')
|
||||
->badge()
|
||||
->color('primary')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('shift.name')
|
||||
->label('Shift')
|
||||
->badge()
|
||||
->color('gray')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('employment_status')
|
||||
->label('Status')
|
||||
->badge()
|
||||
->color(fn (EmploymentStatus $state): string => $state->color())
|
||||
->formatStateUsing(fn (EmploymentStatus $state): string => $state->label())
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('hire_date')
|
||||
->date()
|
||||
->sortable(),
|
||||
TextColumn::make('termination_date')
|
||||
->date()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
TextColumn::make('created_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
TextColumn::make('updated_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
TextColumn::make('deleted_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
])
|
||||
->filters([
|
||||
SelectFilter::make('department_id')
|
||||
->label('Department')
|
||||
->relationship('department', 'name')
|
||||
->searchable()
|
||||
->preload(),
|
||||
SelectFilter::make('position_id')
|
||||
->label('Position')
|
||||
->relationship('position', 'name')
|
||||
->searchable()
|
||||
->preload(),
|
||||
SelectFilter::make('shift_id')
|
||||
->label('Shift')
|
||||
->relationship('shift', 'name')
|
||||
->searchable()
|
||||
->preload(),
|
||||
SelectFilter::make('employment_status')
|
||||
->label('Employment Status')
|
||||
->options(EmploymentStatus::class),
|
||||
TrashedFilter::make(),
|
||||
])
|
||||
->recordActions([
|
||||
ViewAction::make(),
|
||||
EditAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
ExportExcelAction::bulk('exportSelected', \App\Exports\EmployeesExport::class, 'employees.xlsx'),
|
||||
BulkAction::make('changeDepartment')
|
||||
->label('Change Department')
|
||||
->icon('heroicon-o-building-office-2')
|
||||
->schema([
|
||||
Select::make('department_id')
|
||||
->label('Department')
|
||||
->options(fn (): array => Department::query()->orderBy('name')->pluck('name', 'id')->all())
|
||||
->searchable()
|
||||
->required(),
|
||||
])
|
||||
->action(function (Collection $records, array $data): void {
|
||||
$records->each(
|
||||
fn (Employee $employee) => $employee->update([
|
||||
'department_id' => $data['department_id'],
|
||||
]),
|
||||
);
|
||||
})
|
||||
->deselectRecordsAfterCompletion(),
|
||||
DeleteBulkAction::make(),
|
||||
ForceDeleteBulkAction::make(),
|
||||
RestoreBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\Employees\Widgets;
|
||||
|
||||
use App\Models\Employee;
|
||||
use App\Services\Employee\EmployeeStatisticsService;
|
||||
use Filament\Widgets\StatsOverviewWidget;
|
||||
use Filament\Widgets\StatsOverviewWidget\Stat;
|
||||
|
||||
class EmployeeStatsWidget extends StatsOverviewWidget
|
||||
{
|
||||
public ?Employee $record = null;
|
||||
|
||||
protected function getStats(): array
|
||||
{
|
||||
if (! $this->record instanceof Employee) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$summary = app(EmployeeStatisticsService::class)->summary($this->record);
|
||||
|
||||
return [
|
||||
Stat::make('Vacation Taken', (string) $summary->vacationTaken)
|
||||
->description("{$summary->vacationRemaining} days remaining")
|
||||
->descriptionIcon('heroicon-o-calendar')
|
||||
->color('primary')
|
||||
->icon('heroicon-o-sun'),
|
||||
Stat::make('Sick Leaves', (string) $summary->sickLeaveCount)
|
||||
->description('Total records')
|
||||
->descriptionIcon('heroicon-o-heart')
|
||||
->color('warning')
|
||||
->icon('heroicon-o-heart'),
|
||||
Stat::make('Disciplinary Reports', (string) $summary->reportsCount)
|
||||
->description('On file')
|
||||
->descriptionIcon('heroicon-o-exclamation-triangle')
|
||||
->color('danger')
|
||||
->icon('heroicon-o-exclamation-triangle'),
|
||||
Stat::make('Total Bonuses', number_format($summary->bonusesTotal, 2).' TMT')
|
||||
->description("{$summary->giftsCount} gifts received")
|
||||
->descriptionIcon('heroicon-o-gift')
|
||||
->color('success')
|
||||
->icon('heroicon-o-banknotes'),
|
||||
];
|
||||
}
|
||||
}
|
||||
77
app/Filament/Resources/Explanations/ExplanationResource.php
Normal file
77
app/Filament/Resources/Explanations/ExplanationResource.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\Explanations;
|
||||
|
||||
use App\Filament\Resources\Explanations\Pages\CreateExplanation;
|
||||
use App\Filament\Resources\Explanations\Pages\EditExplanation;
|
||||
use App\Filament\Resources\Explanations\Pages\ListExplanations;
|
||||
use App\Filament\Resources\Explanations\Pages\ViewExplanation;
|
||||
use App\Filament\Resources\Explanations\Schemas\ExplanationForm;
|
||||
use App\Filament\Resources\Explanations\Schemas\ExplanationInfolist;
|
||||
use App\Filament\Resources\Explanations\Tables\ExplanationsTable;
|
||||
use App\Models\Explanation;
|
||||
use BackedEnum;
|
||||
use UnitEnum;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\SoftDeletingScope;
|
||||
|
||||
class ExplanationResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Explanation::class;
|
||||
|
||||
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedDocumentText;
|
||||
|
||||
protected static string | UnitEnum | null $navigationGroup = 'Records';
|
||||
|
||||
protected static ?int $navigationSort = 2;
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'reason';
|
||||
|
||||
protected static bool $isGloballySearchable = false;
|
||||
|
||||
public static function form(Schema $schema): Schema
|
||||
{
|
||||
return ExplanationForm::configure($schema);
|
||||
}
|
||||
|
||||
public static function infolist(Schema $schema): Schema
|
||||
{
|
||||
return ExplanationInfolist::configure($schema);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return ExplanationsTable::configure($table);
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ListExplanations::route('/'),
|
||||
'create' => CreateExplanation::route('/create'),
|
||||
'view' => ViewExplanation::route('/{record}'),
|
||||
'edit' => EditExplanation::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
|
||||
public static function getRecordRouteBindingEloquentQuery(): Builder
|
||||
{
|
||||
return parent::getRecordRouteBindingEloquentQuery()
|
||||
->withoutGlobalScopes([
|
||||
SoftDeletingScope::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Explanations\Pages;
|
||||
|
||||
use App\Filament\Resources\Explanations\ExplanationResource;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateExplanation extends CreateRecord
|
||||
{
|
||||
protected static string $resource = ExplanationResource::class;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Explanations\Pages;
|
||||
|
||||
use App\Filament\Resources\Explanations\ExplanationResource;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\ForceDeleteAction;
|
||||
use Filament\Actions\RestoreAction;
|
||||
use Filament\Actions\ViewAction;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditExplanation extends EditRecord
|
||||
{
|
||||
protected static string $resource = ExplanationResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
ViewAction::make(),
|
||||
DeleteAction::make(),
|
||||
ForceDeleteAction::make(),
|
||||
RestoreAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Explanations\Pages;
|
||||
|
||||
use App\Filament\Resources\Explanations\ExplanationResource;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListExplanations extends ListRecords
|
||||
{
|
||||
protected static string $resource = ExplanationResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
CreateAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Explanations\Pages;
|
||||
|
||||
use App\Filament\Resources\Explanations\ExplanationResource;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Resources\Pages\ViewRecord;
|
||||
|
||||
class ViewExplanation extends ViewRecord
|
||||
{
|
||||
protected static string $resource = ExplanationResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
EditAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Explanations\Schemas;
|
||||
|
||||
use App\Filament\Support\HrForm;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Components\Textarea;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class ExplanationForm
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
HrForm::employeeSelect(),
|
||||
DatePicker::make('explanation_date')
|
||||
->required()
|
||||
->default(now()),
|
||||
TextInput::make('reason')
|
||||
->required()
|
||||
->maxLength(255),
|
||||
Textarea::make('description')
|
||||
->required()
|
||||
->rows(4)
|
||||
->columnSpanFull(),
|
||||
HrForm::fileUpload('attachment_path')
|
||||
->label('Attachment')
|
||||
->acceptedFileTypes(['application/pdf', 'image/*'])
|
||||
->maxSize(10240),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Explanations\Schemas;
|
||||
|
||||
use App\Models\Explanation;
|
||||
use Filament\Infolists\Components\TextEntry;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class ExplanationInfolist
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
TextEntry::make('employee.id')
|
||||
->label('Employee'),
|
||||
TextEntry::make('explanation_date')
|
||||
->date(),
|
||||
TextEntry::make('reason'),
|
||||
TextEntry::make('description')
|
||||
->columnSpanFull(),
|
||||
TextEntry::make('attachment_path')
|
||||
->placeholder('-'),
|
||||
TextEntry::make('created_at')
|
||||
->dateTime()
|
||||
->placeholder('-'),
|
||||
TextEntry::make('updated_at')
|
||||
->dateTime()
|
||||
->placeholder('-'),
|
||||
TextEntry::make('deleted_at')
|
||||
->dateTime()
|
||||
->visible(fn (Explanation $record): bool => $record->trashed()),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Explanations\Tables;
|
||||
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ForceDeleteBulkAction;
|
||||
use Filament\Actions\RestoreBulkAction;
|
||||
use Filament\Actions\ViewAction;
|
||||
use Filament\Tables\Columns\IconColumn;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\TrashedFilter;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class ExplanationsTable
|
||||
{
|
||||
public static function configure(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
TextColumn::make('employee.full_name')
|
||||
->label('Employee')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('explanation_date')
|
||||
->date()
|
||||
->sortable(),
|
||||
TextColumn::make('reason')
|
||||
->searchable()
|
||||
->limit(40),
|
||||
TextColumn::make('description')
|
||||
->limit(50)
|
||||
->toggleable(),
|
||||
IconColumn::make('attachment_path')
|
||||
->label('Attachment')
|
||||
->boolean()
|
||||
->trueIcon('heroicon-o-paper-clip')
|
||||
->falseIcon('heroicon-o-minus'),
|
||||
TextColumn::make('created_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
TextColumn::make('updated_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
TextColumn::make('deleted_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
])
|
||||
->filters([
|
||||
TrashedFilter::make(),
|
||||
])
|
||||
->recordActions([
|
||||
ViewAction::make(),
|
||||
EditAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
ForceDeleteBulkAction::make(),
|
||||
RestoreBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
77
app/Filament/Resources/Gifts/GiftResource.php
Normal file
77
app/Filament/Resources/Gifts/GiftResource.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\Gifts;
|
||||
|
||||
use App\Filament\Resources\Gifts\Pages\CreateGift;
|
||||
use App\Filament\Resources\Gifts\Pages\EditGift;
|
||||
use App\Filament\Resources\Gifts\Pages\ListGifts;
|
||||
use App\Filament\Resources\Gifts\Pages\ViewGift;
|
||||
use App\Filament\Resources\Gifts\Schemas\GiftForm;
|
||||
use App\Filament\Resources\Gifts\Schemas\GiftInfolist;
|
||||
use App\Filament\Resources\Gifts\Tables\GiftsTable;
|
||||
use App\Models\Gift;
|
||||
use BackedEnum;
|
||||
use UnitEnum;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\SoftDeletingScope;
|
||||
|
||||
class GiftResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Gift::class;
|
||||
|
||||
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedGift;
|
||||
|
||||
protected static string | UnitEnum | null $navigationGroup = 'Records';
|
||||
|
||||
protected static ?int $navigationSort = 4;
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'gift_name';
|
||||
|
||||
protected static bool $isGloballySearchable = false;
|
||||
|
||||
public static function form(Schema $schema): Schema
|
||||
{
|
||||
return GiftForm::configure($schema);
|
||||
}
|
||||
|
||||
public static function infolist(Schema $schema): Schema
|
||||
{
|
||||
return GiftInfolist::configure($schema);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return GiftsTable::configure($table);
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ListGifts::route('/'),
|
||||
'create' => CreateGift::route('/create'),
|
||||
'view' => ViewGift::route('/{record}'),
|
||||
'edit' => EditGift::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
|
||||
public static function getRecordRouteBindingEloquentQuery(): Builder
|
||||
{
|
||||
return parent::getRecordRouteBindingEloquentQuery()
|
||||
->withoutGlobalScopes([
|
||||
SoftDeletingScope::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
11
app/Filament/Resources/Gifts/Pages/CreateGift.php
Normal file
11
app/Filament/Resources/Gifts/Pages/CreateGift.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Gifts\Pages;
|
||||
|
||||
use App\Filament\Resources\Gifts\GiftResource;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateGift extends CreateRecord
|
||||
{
|
||||
protected static string $resource = GiftResource::class;
|
||||
}
|
||||
25
app/Filament/Resources/Gifts/Pages/EditGift.php
Normal file
25
app/Filament/Resources/Gifts/Pages/EditGift.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Gifts\Pages;
|
||||
|
||||
use App\Filament\Resources\Gifts\GiftResource;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\ForceDeleteAction;
|
||||
use Filament\Actions\RestoreAction;
|
||||
use Filament\Actions\ViewAction;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditGift extends EditRecord
|
||||
{
|
||||
protected static string $resource = GiftResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
ViewAction::make(),
|
||||
DeleteAction::make(),
|
||||
ForceDeleteAction::make(),
|
||||
RestoreAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
19
app/Filament/Resources/Gifts/Pages/ListGifts.php
Normal file
19
app/Filament/Resources/Gifts/Pages/ListGifts.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Gifts\Pages;
|
||||
|
||||
use App\Filament\Resources\Gifts\GiftResource;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListGifts extends ListRecords
|
||||
{
|
||||
protected static string $resource = GiftResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
CreateAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
19
app/Filament/Resources/Gifts/Pages/ViewGift.php
Normal file
19
app/Filament/Resources/Gifts/Pages/ViewGift.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Gifts\Pages;
|
||||
|
||||
use App\Filament\Resources\Gifts\GiftResource;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Resources\Pages\ViewRecord;
|
||||
|
||||
class ViewGift extends ViewRecord
|
||||
{
|
||||
protected static string $resource = GiftResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
EditAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
37
app/Filament/Resources/Gifts/Schemas/GiftForm.php
Normal file
37
app/Filament/Resources/Gifts/Schemas/GiftForm.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Gifts\Schemas;
|
||||
|
||||
use App\Filament\Support\HrForm;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Components\Textarea;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class GiftForm
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
HrForm::employeeSelect(),
|
||||
DatePicker::make('gift_date')
|
||||
->required()
|
||||
->default(now()),
|
||||
TextInput::make('gift_name')
|
||||
->label('Gift Name')
|
||||
->required()
|
||||
->maxLength(255),
|
||||
TextInput::make('value')
|
||||
->required()
|
||||
->numeric()
|
||||
->prefix('TMT')
|
||||
->minValue(0)
|
||||
->step(0.01)
|
||||
->default(0),
|
||||
Textarea::make('reason')
|
||||
->rows(3)
|
||||
->columnSpanFull(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
36
app/Filament/Resources/Gifts/Schemas/GiftInfolist.php
Normal file
36
app/Filament/Resources/Gifts/Schemas/GiftInfolist.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Gifts\Schemas;
|
||||
|
||||
use App\Models\Gift;
|
||||
use Filament\Infolists\Components\TextEntry;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class GiftInfolist
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
TextEntry::make('employee.id')
|
||||
->label('Employee'),
|
||||
TextEntry::make('gift_date')
|
||||
->date(),
|
||||
TextEntry::make('gift_name'),
|
||||
TextEntry::make('value')
|
||||
->numeric(),
|
||||
TextEntry::make('reason')
|
||||
->placeholder('-')
|
||||
->columnSpanFull(),
|
||||
TextEntry::make('created_at')
|
||||
->dateTime()
|
||||
->placeholder('-'),
|
||||
TextEntry::make('updated_at')
|
||||
->dateTime()
|
||||
->placeholder('-'),
|
||||
TextEntry::make('deleted_at')
|
||||
->dateTime()
|
||||
->visible(fn (Gift $record): bool => $record->trashed()),
|
||||
]);
|
||||
}
|
||||
}
|
||||
66
app/Filament/Resources/Gifts/Tables/GiftsTable.php
Normal file
66
app/Filament/Resources/Gifts/Tables/GiftsTable.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Gifts\Tables;
|
||||
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ForceDeleteBulkAction;
|
||||
use Filament\Actions\RestoreBulkAction;
|
||||
use Filament\Actions\ViewAction;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\TrashedFilter;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class GiftsTable
|
||||
{
|
||||
public static function configure(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
TextColumn::make('employee.full_name')
|
||||
->label('Employee')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('gift_date')
|
||||
->date()
|
||||
->sortable(),
|
||||
TextColumn::make('gift_name')
|
||||
->label('Gift')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('value')
|
||||
->money('TMT')
|
||||
->sortable(),
|
||||
TextColumn::make('reason')
|
||||
->limit(40)
|
||||
->toggleable(),
|
||||
TextColumn::make('created_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
TextColumn::make('updated_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
TextColumn::make('deleted_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
])
|
||||
->filters([
|
||||
TrashedFilter::make(),
|
||||
])
|
||||
->recordActions([
|
||||
ViewAction::make(),
|
||||
EditAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
ForceDeleteBulkAction::make(),
|
||||
RestoreBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
11
app/Filament/Resources/Positions/Pages/CreatePosition.php
Normal file
11
app/Filament/Resources/Positions/Pages/CreatePosition.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Positions\Pages;
|
||||
|
||||
use App\Filament\Resources\Positions\PositionResource;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreatePosition extends CreateRecord
|
||||
{
|
||||
protected static string $resource = PositionResource::class;
|
||||
}
|
||||
25
app/Filament/Resources/Positions/Pages/EditPosition.php
Normal file
25
app/Filament/Resources/Positions/Pages/EditPosition.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Positions\Pages;
|
||||
|
||||
use App\Filament\Resources\Positions\PositionResource;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\ForceDeleteAction;
|
||||
use Filament\Actions\RestoreAction;
|
||||
use Filament\Actions\ViewAction;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditPosition extends EditRecord
|
||||
{
|
||||
protected static string $resource = PositionResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
ViewAction::make(),
|
||||
DeleteAction::make(),
|
||||
ForceDeleteAction::make(),
|
||||
RestoreAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
19
app/Filament/Resources/Positions/Pages/ListPositions.php
Normal file
19
app/Filament/Resources/Positions/Pages/ListPositions.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Positions\Pages;
|
||||
|
||||
use App\Filament\Resources\Positions\PositionResource;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListPositions extends ListRecords
|
||||
{
|
||||
protected static string $resource = PositionResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
CreateAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
19
app/Filament/Resources/Positions/Pages/ViewPosition.php
Normal file
19
app/Filament/Resources/Positions/Pages/ViewPosition.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Positions\Pages;
|
||||
|
||||
use App\Filament\Resources\Positions\PositionResource;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Resources\Pages\ViewRecord;
|
||||
|
||||
class ViewPosition extends ViewRecord
|
||||
{
|
||||
protected static string $resource = PositionResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
EditAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
77
app/Filament/Resources/Positions/PositionResource.php
Normal file
77
app/Filament/Resources/Positions/PositionResource.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\Positions;
|
||||
|
||||
use App\Filament\Resources\Positions\Pages\CreatePosition;
|
||||
use App\Filament\Resources\Positions\Pages\EditPosition;
|
||||
use App\Filament\Resources\Positions\Pages\ListPositions;
|
||||
use App\Filament\Resources\Positions\Pages\ViewPosition;
|
||||
use App\Filament\Resources\Positions\Schemas\PositionForm;
|
||||
use App\Filament\Resources\Positions\Schemas\PositionInfolist;
|
||||
use App\Filament\Resources\Positions\Tables\PositionsTable;
|
||||
use App\Models\Position;
|
||||
use BackedEnum;
|
||||
use UnitEnum;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\SoftDeletingScope;
|
||||
|
||||
class PositionResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Position::class;
|
||||
|
||||
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedBriefcase;
|
||||
|
||||
protected static string | UnitEnum | null $navigationGroup = 'Organization';
|
||||
|
||||
protected static ?int $navigationSort = 2;
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'name';
|
||||
|
||||
protected static bool $isGloballySearchable = false;
|
||||
|
||||
public static function form(Schema $schema): Schema
|
||||
{
|
||||
return PositionForm::configure($schema);
|
||||
}
|
||||
|
||||
public static function infolist(Schema $schema): Schema
|
||||
{
|
||||
return PositionInfolist::configure($schema);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return PositionsTable::configure($table);
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ListPositions::route('/'),
|
||||
'create' => CreatePosition::route('/create'),
|
||||
'view' => ViewPosition::route('/{record}'),
|
||||
'edit' => EditPosition::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
|
||||
public static function getRecordRouteBindingEloquentQuery(): Builder
|
||||
{
|
||||
return parent::getRecordRouteBindingEloquentQuery()
|
||||
->withoutGlobalScopes([
|
||||
SoftDeletingScope::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
23
app/Filament/Resources/Positions/Schemas/PositionForm.php
Normal file
23
app/Filament/Resources/Positions/Schemas/PositionForm.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Positions\Schemas;
|
||||
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Components\Textarea;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class PositionForm
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
TextInput::make('name')
|
||||
->required()
|
||||
->maxLength(255),
|
||||
Textarea::make('description')
|
||||
->rows(3)
|
||||
->columnSpanFull(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Positions\Schemas;
|
||||
|
||||
use App\Models\Position;
|
||||
use Filament\Infolists\Components\TextEntry;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class PositionInfolist
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
TextEntry::make('name'),
|
||||
TextEntry::make('description')
|
||||
->placeholder('-')
|
||||
->columnSpanFull(),
|
||||
TextEntry::make('created_at')
|
||||
->dateTime()
|
||||
->placeholder('-'),
|
||||
TextEntry::make('updated_at')
|
||||
->dateTime()
|
||||
->placeholder('-'),
|
||||
TextEntry::make('deleted_at')
|
||||
->dateTime()
|
||||
->visible(fn (Position $record): bool => $record->trashed()),
|
||||
]);
|
||||
}
|
||||
}
|
||||
56
app/Filament/Resources/Positions/Tables/PositionsTable.php
Normal file
56
app/Filament/Resources/Positions/Tables/PositionsTable.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Positions\Tables;
|
||||
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ForceDeleteBulkAction;
|
||||
use Filament\Actions\RestoreBulkAction;
|
||||
use Filament\Actions\ViewAction;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\TrashedFilter;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class PositionsTable
|
||||
{
|
||||
public static function configure(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
TextColumn::make('name')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('description')
|
||||
->searchable()
|
||||
->limit(50)
|
||||
->toggleable(),
|
||||
TextColumn::make('created_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
TextColumn::make('updated_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
TextColumn::make('deleted_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
])
|
||||
->filters([
|
||||
TrashedFilter::make(),
|
||||
])
|
||||
->recordActions([
|
||||
ViewAction::make(),
|
||||
EditAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
ForceDeleteBulkAction::make(),
|
||||
RestoreBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
11
app/Filament/Resources/Shifts/Pages/CreateShift.php
Normal file
11
app/Filament/Resources/Shifts/Pages/CreateShift.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Shifts\Pages;
|
||||
|
||||
use App\Filament\Resources\Shifts\ShiftResource;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateShift extends CreateRecord
|
||||
{
|
||||
protected static string $resource = ShiftResource::class;
|
||||
}
|
||||
25
app/Filament/Resources/Shifts/Pages/EditShift.php
Normal file
25
app/Filament/Resources/Shifts/Pages/EditShift.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Shifts\Pages;
|
||||
|
||||
use App\Filament\Resources\Shifts\ShiftResource;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\ForceDeleteAction;
|
||||
use Filament\Actions\RestoreAction;
|
||||
use Filament\Actions\ViewAction;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditShift extends EditRecord
|
||||
{
|
||||
protected static string $resource = ShiftResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
ViewAction::make(),
|
||||
DeleteAction::make(),
|
||||
ForceDeleteAction::make(),
|
||||
RestoreAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user