This commit is contained in:
fatihalp 2026-03-06 02:28:46 +03:00
parent aa7d2e27c0
commit 08d0b68349
4 changed files with 118 additions and 173 deletions

View File

@ -2,6 +2,7 @@
namespace Modules\Admin\Filament\Pages;
use App\Support\HomeSlideDefaults;
use App\Support\CountryCodeManager;
use App\Settings\GeneralSettings;
use BackedEnum;
@ -22,13 +23,13 @@ class ManageGeneralSettings extends SettingsPage
{
protected static string $settings = GeneralSettings::class;
protected static ?string $title = 'General Settings';
protected static ?string $title = 'Genel Ayarlar';
protected static ?string $navigationLabel = 'General Settings';
protected static ?string $navigationLabel = 'Genel Ayarlar';
protected static string | BackedEnum | null $navigationIcon = 'heroicon-o-cog-6-tooth';
protected static string | UnitEnum | null $navigationGroup = 'Settings';
protected static string | UnitEnum | null $navigationGroup = 'Ayarlar';
protected static ?int $navigationSort = 1;
@ -37,35 +38,35 @@ class ManageGeneralSettings extends SettingsPage
return $schema
->components([
TextInput::make('site_name')
->label('Site Name')
->label('Site Adı')
->required()
->maxLength(255),
Textarea::make('site_description')
->label('Site Description')
->label('Site ıklaması')
->rows(3)
->maxLength(500),
Repeater::make('home_slides')
->label('Home Slider')
->label('Ana Sayfa Slider')
->schema([
TextInput::make('badge')
->label('Badge')
->label('Rozet')
->required()
->maxLength(255),
TextInput::make('title')
->label('Title')
->label('Başlık')
->required()
->maxLength(255),
Textarea::make('subtitle')
->label('Subtitle')
->label('Alt Başlık')
->rows(2)
->required()
->maxLength(500),
TextInput::make('primary_button_text')
->label('Primary Button Text')
->label('Birincil Buton Metni')
->required()
->maxLength(120),
TextInput::make('secondary_button_text')
->label('Secondary Button Text')
->label('İkincil Buton Metni')
->required()
->maxLength(120),
])
@ -73,39 +74,39 @@ class ManageGeneralSettings extends SettingsPage
->minItems(1)
->collapsible()
->reorderableWithButtons()
->addActionLabel('Add Slide')
->addActionLabel('Slide Ekle')
->itemLabel(fn (array $state): ?string => filled($state['title'] ?? null) ? (string) $state['title'] : 'Slide')
->afterStateHydrated(fn (Repeater $component, $state) => $component->state($this->normalizeHomeSlides($state)))
->dehydrateStateUsing(fn ($state) => $this->normalizeHomeSlides($state)),
FileUpload::make('site_logo')
->label('Site Logo')
->label('Site Logosu')
->image()
->disk('public')
->directory('settings')
->visibility('public'),
TextInput::make('sender_name')
->label('Sender Name')
->label('Gönderici Adı')
->required()
->maxLength(120),
TextInput::make('sender_email')
->label('Sender Email')
->label('Gönderici E-postası')
->email()
->required()
->maxLength(255),
Select::make('default_language')
->label('Default Language')
->label('Varsayılan Dil')
->options($this->localeOptions())
->required()
->searchable(),
CountryCodeSelect::make('default_country_code')
->label('Default Country')
->label('Varsayılan Ülke')
->default('+90')
->required()
->helperText('Used as default country in panel forms.'),
->helperText('Panel formlarında varsayılan ülke olarak kullanılır.'),
TagsInput::make('currencies')
->label('Currencies')
->placeholder('USD')
->helperText('Add 3-letter currency codes like USD, EUR, TRY.')
->label('Para Birimleri')
->placeholder('TRY')
->helperText('TRY, USD, EUR gibi 3 harfli para birimi kodları ekleyin.')
->required()
->rules(['array', 'min:1'])
->afterStateHydrated(fn (TagsInput $component, $state) => $component->state($this->normalizeCurrencies($state)))
@ -125,19 +126,19 @@ class ManageGeneralSettings extends SettingsPage
->defaultCountry(CountryCodeManager::defaultCountryIso2())
->nullable()
->formatAsYouType()
->helperText('Use international format, e.g. +905551112233.'),
->helperText('Uluslararası format kullanın. Örnek: +905551112233'),
Toggle::make('enable_google_maps')
->label('Enable Google Maps')
->label('Google Maps Aktif')
->default(false),
TextInput::make('google_maps_api_key')
->label('Google Maps API Key')
->label('Google Maps API Anahtarı')
->password()
->revealable()
->nullable()
->maxLength(255)
->helperText('Required to enable map fields in listing forms.'),
->helperText('İlan formlarındaki harita alanlarını açmak için gereklidir.'),
Toggle::make('enable_google_login')
->label('Enable Google Login')
->label('Google ile Giriş Aktif')
->default(false),
TextInput::make('google_client_id')
->label('Google Client ID')
@ -150,7 +151,7 @@ class ManageGeneralSettings extends SettingsPage
->nullable()
->maxLength(255),
Toggle::make('enable_facebook_login')
->label('Enable Facebook Login')
->label('Facebook ile Giriş Aktif')
->default(false),
TextInput::make('facebook_client_id')
->label('Facebook Client ID')
@ -163,7 +164,7 @@ class ManageGeneralSettings extends SettingsPage
->nullable()
->maxLength(255),
Toggle::make('enable_apple_login')
->label('Enable Apple Login')
->label('Apple ile Giriş Aktif')
->default(false),
TextInput::make('apple_client_id')
->label('Apple Client ID')
@ -183,14 +184,6 @@ class ManageGeneralSettings extends SettingsPage
$labels = [
'en' => 'English',
'tr' => 'Türkçe',
'ar' => 'العربية',
'zh' => '中文',
'es' => 'Español',
'fr' => 'Français',
'de' => 'Deutsch',
'pt' => 'Português',
'ru' => 'Русский',
'ja' => '日本語',
];
return collect(config('app.available_locales', ['en']))
@ -215,47 +208,11 @@ class ManageGeneralSettings extends SettingsPage
private function defaultHomeSlides(): array
{
return [
[
'badge' => 'OpenClassify Marketplace',
'title' => 'İlan ücreti ödemeden ürününü hızla sat!',
'subtitle' => 'Buy and sell everything in your area',
'primary_button_text' => 'İncele',
'secondary_button_text' => 'Post Listing',
],
];
return HomeSlideDefaults::defaults();
}
private function normalizeHomeSlides(mixed $state): array
{
$slides = is_array($state) ? $state : [];
$fallbackSlide = $this->defaultHomeSlides()[0];
$normalized = collect($slides)
->filter(fn ($slide): bool => is_array($slide))
->map(function (array $slide) use ($fallbackSlide): ?array {
$badge = trim((string) ($slide['badge'] ?? ''));
$title = trim((string) ($slide['title'] ?? ''));
$subtitle = trim((string) ($slide['subtitle'] ?? ''));
$primaryButtonText = trim((string) ($slide['primary_button_text'] ?? ''));
$secondaryButtonText = trim((string) ($slide['secondary_button_text'] ?? ''));
if ($title === '') {
return null;
}
return [
'badge' => $badge !== '' ? $badge : $fallbackSlide['badge'],
'title' => $title,
'subtitle' => $subtitle !== '' ? $subtitle : $fallbackSlide['subtitle'],
'primary_button_text' => $primaryButtonText !== '' ? $primaryButtonText : $fallbackSlide['primary_button_text'],
'secondary_button_text' => $secondaryButtonText !== '' ? $secondaryButtonText : $fallbackSlide['secondary_button_text'],
];
})
->filter(fn ($slide): bool => is_array($slide))
->values()
->all();
return $normalized !== [] ? $normalized : $this->defaultHomeSlides();
return HomeSlideDefaults::normalize($state);
}
}

View File

@ -3,6 +3,7 @@
namespace App\Providers;
use App\Support\CountryCodeManager;
use App\Support\HomeSlideDefaults;
use App\Settings\GeneralSettings;
use BezhanSalleh\LanguageSwitch\LanguageSwitch;
use Illuminate\Support\ServiceProvider;
@ -36,9 +37,9 @@ class AppServiceProvider extends ServiceProvider
View::addNamespace('app', resource_path('views'));
$fallbackName = config('app.name', 'OpenClassify');
$fallbackLocale = config('app.locale', 'en');
$fallbackLocale = config('app.locale', 'tr');
$fallbackCurrencies = $this->normalizeCurrencies(config('app.currencies', ['USD']));
$fallbackDescription = 'The marketplace for buying and selling everything.';
$fallbackDescription = 'Alım satım için hızlı ve güvenli ilan platformu.';
$fallbackHomeSlides = $this->defaultHomeSlides();
$fallbackGoogleMapsApiKey = env('GOOGLE_MAPS_API_KEY');
$fallbackGoogleClientId = env('GOOGLE_CLIENT_ID');
@ -100,7 +101,7 @@ class AppServiceProvider extends ServiceProvider
$appleClientId = trim((string) ($settings->apple_client_id ?: $fallbackAppleClientId));
$appleClientSecret = trim((string) ($settings->apple_client_secret ?: $fallbackAppleClientSecret));
$defaultCountryCode = CountryCodeManager::normalizeCountryCode($settings->default_country_code ?? $fallbackDefaultCountryCode);
$homeSlides = $this->normalizeHomeSlides($settings->home_slides ?? [], $fallbackHomeSlides);
$homeSlides = $this->normalizeHomeSlides($settings->home_slides ?? []);
$generalSettings = [
'site_name' => trim((string) ($settings->site_name ?: $fallbackName)),
@ -178,14 +179,6 @@ class AppServiceProvider extends ServiceProvider
$localeLabels = [
'en' => 'English',
'tr' => 'Türkçe',
'ar' => 'العربية',
'zh' => '中文',
'es' => 'Español',
'fr' => 'Français',
'de' => 'Deutsch',
'pt' => 'Português',
'ru' => 'Русский',
'ja' => '日本語',
];
LanguageSwitch::configureUsing(function (LanguageSwitch $switch) use ($availableLocales, $localeLabels): void {
@ -260,56 +253,11 @@ class AppServiceProvider extends ServiceProvider
private function defaultHomeSlides(): array
{
return [
[
'badge' => 'OpenClassify Marketplace',
'title' => 'İlan ücreti ödemeden ürününü hızla sat!',
'subtitle' => 'Buy and sell everything in your area',
'primary_button_text' => 'İncele',
'secondary_button_text' => 'Post Listing',
],
];
return HomeSlideDefaults::defaults();
}
private function normalizeHomeSlides(mixed $slides, array $fallbackSlides): array
private function normalizeHomeSlides(mixed $slides): array
{
if (! is_array($slides)) {
return $fallbackSlides;
}
$fallbackSlide = $fallbackSlides[0] ?? [
'badge' => 'OpenClassify Marketplace',
'title' => 'İlan ücreti ödemeden ürününü hızla sat!',
'subtitle' => 'Buy and sell everything in your area',
'primary_button_text' => 'İncele',
'secondary_button_text' => 'Post Listing',
];
$normalized = collect($slides)
->filter(fn ($slide): bool => is_array($slide))
->map(function (array $slide) use ($fallbackSlide): ?array {
$badge = trim((string) ($slide['badge'] ?? ''));
$title = trim((string) ($slide['title'] ?? ''));
$subtitle = trim((string) ($slide['subtitle'] ?? ''));
$primaryButtonText = trim((string) ($slide['primary_button_text'] ?? ''));
$secondaryButtonText = trim((string) ($slide['secondary_button_text'] ?? ''));
if ($title === '') {
return null;
}
return [
'badge' => $badge !== '' ? $badge : $fallbackSlide['badge'],
'title' => $title,
'subtitle' => $subtitle !== '' ? $subtitle : $fallbackSlide['subtitle'],
'primary_button_text' => $primaryButtonText !== '' ? $primaryButtonText : $fallbackSlide['primary_button_text'],
'secondary_button_text' => $secondaryButtonText !== '' ? $secondaryButtonText : $fallbackSlide['secondary_button_text'],
];
})
->filter(fn ($slide): bool => is_array($slide))
->values()
->all();
return $normalized !== [] ? $normalized : $fallbackSlides;
return HomeSlideDefaults::normalize($slides);
}
}

View File

@ -0,0 +1,77 @@
<?php
namespace App\Support;
final class HomeSlideDefaults
{
/**
* @return array<int, array{badge: string, title: string, subtitle: string, primary_button_text: string, secondary_button_text: string}>
*/
public static function defaults(): array
{
return [
[
'badge' => 'Vitrin İlanları',
'title' => 'İlan ücreti ödemeden ürününü dakikalar içinde yayına al.',
'subtitle' => 'Mahallendeki alıcılarla hızlıca buluş, pazarlığı doğrudan mesajla tamamla.',
'primary_button_text' => 'İlanları İncele',
'secondary_button_text' => 'İlan Ver',
],
[
'badge' => 'Günün Fırsatları',
'title' => 'Elektronikten araca kadar her kategoride canlı ilanlar seni bekliyor.',
'subtitle' => 'Kategorilere göz at, favorilerine ekle ve satıcılarla tek tıkla iletişime geç.',
'primary_button_text' => 'Kategorileri Gör',
'secondary_button_text' => 'Hemen Başla',
],
[
'badge' => 'Yerel Alışveriş',
'title' => 'Konumuna en yakın ikinci el fırsatları tek ekranda keşfet.',
'subtitle' => 'Şehrini seç, sana en yakın ilanları filtrele ve güvenle alışveriş yap.',
'primary_button_text' => 'Yakındaki İlanlar',
'secondary_button_text' => 'Ücretsiz İlan Ver',
],
];
}
/**
* @return array<int, array{badge: string, title: string, subtitle: string, primary_button_text: string, secondary_button_text: string}>
*/
public static function normalize(mixed $slides): array
{
$defaults = self::defaults();
$source = is_array($slides) ? $slides : [];
$normalized = collect($source)
->filter(fn ($slide): bool => is_array($slide))
->values()
->map(function (array $slide, int $index) use ($defaults): ?array {
$fallback = $defaults[$index] ?? $defaults[array_key_last($defaults)];
$badge = trim((string) ($slide['badge'] ?? ''));
$title = trim((string) ($slide['title'] ?? ''));
$subtitle = trim((string) ($slide['subtitle'] ?? ''));
$primaryButtonText = trim((string) ($slide['primary_button_text'] ?? ''));
$secondaryButtonText = trim((string) ($slide['secondary_button_text'] ?? ''));
if ($title === '') {
return null;
}
return [
'badge' => $badge !== '' ? $badge : $fallback['badge'],
'title' => $title,
'subtitle' => $subtitle !== '' ? $subtitle : $fallback['subtitle'],
'primary_button_text' => $primaryButtonText !== '' ? $primaryButtonText : $fallback['primary_button_text'],
'secondary_button_text' => $secondaryButtonText !== '' ? $secondaryButtonText : $fallback['secondary_button_text'],
];
})
->filter(fn ($slide): bool => is_array($slide))
->values();
return $normalized
->concat(collect($defaults)->slice($normalized->count()))
->take(count($defaults))
->values()
->all();
}
}

View File

@ -2,6 +2,7 @@
namespace Database\Seeders;
use App\Support\HomeSlideDefaults;
use App\Settings\GeneralSettings;
use Illuminate\Database\Seeder;
@ -10,51 +11,13 @@ class HomeSliderSettingsSeeder extends Seeder
public function run(): void
{
$settings = app(GeneralSettings::class);
$fallbackSlide = $this->defaultHomeSlides()[0];
$slides = is_array($settings->home_slides ?? null) ? $settings->home_slides : [];
$normalized = collect($slides)
->filter(fn ($slide): bool => is_array($slide))
->map(function (array $slide) use ($fallbackSlide): ?array {
$title = trim((string) ($slide['title'] ?? ''));
if ($title === '') {
return null;
}
$badge = trim((string) ($slide['badge'] ?? ''));
$subtitle = trim((string) ($slide['subtitle'] ?? ''));
$primaryButtonText = trim((string) ($slide['primary_button_text'] ?? ''));
$secondaryButtonText = trim((string) ($slide['secondary_button_text'] ?? ''));
return [
'badge' => $badge !== '' ? $badge : $fallbackSlide['badge'],
'title' => $title,
'subtitle' => $subtitle !== '' ? $subtitle : $fallbackSlide['subtitle'],
'primary_button_text' => $primaryButtonText !== '' ? $primaryButtonText : $fallbackSlide['primary_button_text'],
'secondary_button_text' => $secondaryButtonText !== '' ? $secondaryButtonText : $fallbackSlide['secondary_button_text'],
];
})
->filter(fn ($slide): bool => is_array($slide))
->values()
->all();
$settings->home_slides = $normalized !== [] ? $normalized : $this->defaultHomeSlides();
$settings->home_slides = HomeSlideDefaults::normalize($settings->home_slides ?? []);
$settings->save();
}
private function defaultHomeSlides(): array
{
return [
[
'badge' => 'OpenClassify Marketplace',
'title' => 'İlan ücreti ödemeden ürününü hızla sat!',
'subtitle' => 'Buy and sell everything in your area',
'primary_button_text' => 'İncele',
'secondary_button_text' => 'Post Listing',
],
];
return HomeSlideDefaults::defaults();
}
}