- IP pool: sheet import (xlsx/csv) matched by address, bulk allocate/revoke with notification email (ip_allocated/ip_revoked), ip_pool_logs history. - Orders/invoices: Excel export on branded template (BrandedReportWriter), shared billing filters, order item service info in list responses. - Web design quote Excel export; activity log export. - Service attachments with copy-to-invoice; deployment invoice attachments. - Customer email attachments stored on disk and attached by path. - Admin password change endpoint; user.fullname backfill migration; orders.user_id backfill from logs. - Disable deploy workflow until CI/CD is set up. - Ignore stored customer email and service attachment uploads. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
88 lines
2.4 KiB
PHP
88 lines
2.4 KiB
PHP
<?php
|
|
|
|
namespace App\Enums\WebDesign;
|
|
|
|
enum WebDesignPlatform: string
|
|
{
|
|
case WORDPRESS_ELEMENTOR = 'wordpress_elementor';
|
|
case WORDPRESS_HEADLESS = 'wordpress_headless';
|
|
case LARAVEL = 'laravel';
|
|
case NESTJS = 'nestjs';
|
|
case SPRING_BOOT = 'spring_boot';
|
|
|
|
public function label(): string
|
|
{
|
|
return match ($this) {
|
|
self::WORDPRESS_ELEMENTOR => 'WordPress + Elementor',
|
|
self::WORDPRESS_HEADLESS => 'WordPress Headless',
|
|
self::LARAVEL => 'Laravel',
|
|
self::NESTJS => 'NestJS',
|
|
self::SPRING_BOOT => 'Spring Boot',
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Các framework frontend cho phép theo từng nền tảng.
|
|
* Mảng rỗng = không có lựa chọn frontend riêng.
|
|
*/
|
|
public function frontendOptions(): array
|
|
{
|
|
return match ($this) {
|
|
self::WORDPRESS_ELEMENTOR => [],
|
|
self::WORDPRESS_HEADLESS => ['nextjs', 'astro', 'vue', 'react', 'nuxt', 'angular'],
|
|
self::LARAVEL, self::NESTJS => ['react', 'nextjs', 'nuxt', 'vue'],
|
|
self::SPRING_BOOT => ['react', 'nextjs', 'nuxt', 'vue', 'angular'],
|
|
};
|
|
}
|
|
|
|
public function defaultFrontend(): ?string
|
|
{
|
|
return match ($this) {
|
|
self::WORDPRESS_ELEMENTOR => null,
|
|
self::WORDPRESS_HEADLESS => 'nextjs',
|
|
self::LARAVEL, self::NESTJS => 'react',
|
|
self::SPRING_BOOT => 'react',
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Từ gói Laravel trở lên có thể custom admin.
|
|
*/
|
|
public function supportsCustomAdmin(): bool
|
|
{
|
|
return match ($this) {
|
|
self::WORDPRESS_ELEMENTOR, self::WORDPRESS_HEADLESS => false,
|
|
self::LARAVEL, self::NESTJS, self::SPRING_BOOT => true,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Phụ phí bản quyền hằng năm theo USD (Elementor Pro).
|
|
*/
|
|
public function annualLicenseFeeUsd(): int
|
|
{
|
|
return $this === self::WORDPRESS_ELEMENTOR ? 60 : 0;
|
|
}
|
|
|
|
public static function frontendLabel(?string $framework): ?string
|
|
{
|
|
if (!$framework) {
|
|
return null;
|
|
}
|
|
|
|
return [
|
|
'nextjs' => 'Next.js',
|
|
'react' => 'React',
|
|
'vue' => 'Vue',
|
|
'nuxt' => 'Nuxt',
|
|
'astro' => 'Astro',
|
|
'angular' => 'Angular',
|
|
][$framework] ?? $framework;
|
|
}
|
|
|
|
public static function values(): array
|
|
{
|
|
return array_column(self::cases(), 'value');
|
|
}
|
|
}
|