feat: integrate homepage settings management in Admin and HomeController, enhancing homepage configuration capabilities
This commit is contained in:
parent
67ee140ba7
commit
6273d1a31d
@ -4,10 +4,12 @@
|
||||
|
||||
use App\Http\Controllers\Concerns\FlashesEntityMessage;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Admin\System\Setting\HomepageSettingRequest;
|
||||
use App\Http\Requests\Admin\System\Setting\HrSettingRequest;
|
||||
use App\Http\Requests\Admin\System\Setting\MarketplaceRequest;
|
||||
use App\Http\Requests\Admin\System\Setting\SocialMediaRequest;
|
||||
use App\Http\Requests\Admin\System\Setting\SystemRequest;
|
||||
use App\Services\System\Setting\HomepageSettingService;
|
||||
use App\Services\System\Setting\HrSettingService;
|
||||
use App\Services\System\Setting\MarketplaceService;
|
||||
use App\Services\System\Setting\SocialMediaService;
|
||||
@ -25,6 +27,7 @@ public function __construct(
|
||||
private readonly SocialMediaService $socialMediaService,
|
||||
private readonly MarketplaceService $marketplaceService,
|
||||
private readonly HrSettingService $hrSettingService,
|
||||
private readonly HomepageSettingService $homepageSettingService,
|
||||
) {}
|
||||
|
||||
public function index(): Response
|
||||
@ -34,6 +37,7 @@ public function index(): Response
|
||||
'socialMedia' => $this->socialMediaService->socialMediaData(),
|
||||
'marketplace' => $this->marketplaceService->marketplaceData(),
|
||||
'hr' => $this->hrSettingService->hrData(),
|
||||
'homepage' => $this->homepageSettingService->homepageData(),
|
||||
]);
|
||||
}
|
||||
|
||||
@ -72,4 +76,13 @@ public function updateHr(HrSettingRequest $request): RedirectResponse
|
||||
|
||||
return redirect()->route('admin.system.setting.index');
|
||||
}
|
||||
|
||||
public function updateHomepage(HomepageSettingRequest $request): RedirectResponse
|
||||
{
|
||||
$this->homepageSettingService->updateHomepage($request->validated());
|
||||
|
||||
$this->flashSuccess('Pengaturan homepage berhasil disimpan.');
|
||||
|
||||
return redirect()->route('admin.system.setting.index');
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
use App\Models\Product;
|
||||
use App\Models\SystemConfiguration;
|
||||
use App\Services\Manage\CuttingResultPriceResolver;
|
||||
use App\Services\System\Setting\HomepageSettingService;
|
||||
use App\Settings\SocialMediaSettings;
|
||||
use App\Settings\SystemSettings;
|
||||
use App\Support\Media\MediaPresenter;
|
||||
@ -17,6 +18,7 @@ class HomeController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly CuttingResultPriceResolver $cuttingResultPriceResolver,
|
||||
private readonly HomepageSettingService $homepageSettingService,
|
||||
) {}
|
||||
|
||||
public function index(): Response
|
||||
@ -60,10 +62,12 @@ public function index(): Response
|
||||
$settings = app(SystemSettings::class);
|
||||
$socialSettings = app(SocialMediaSettings::class);
|
||||
|
||||
$appName = $settings->app_name ?? 'DST Collection';
|
||||
|
||||
return Inertia::render('Home', [
|
||||
'categories' => $categories,
|
||||
'products' => $products,
|
||||
'appName' => $settings->app_name ?? 'DST Collection',
|
||||
'appName' => $appName,
|
||||
'aboutApp' => $settings->about_app ?? '',
|
||||
'contactEmail' => $settings->email ?? '',
|
||||
'contactPhone' => $settings->phone ?? '',
|
||||
@ -72,6 +76,7 @@ public function index(): Response
|
||||
'instagramUrl' => $socialSettings->instagram_url ?? null,
|
||||
'facebookUrl' => $socialSettings->facebook_url ?? null,
|
||||
'tiktokUrl' => $socialSettings->tiktok_url ?? null,
|
||||
'homepage' => $this->homepageSettingService->homepageData(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Admin\System\Setting;
|
||||
|
||||
use App\Enums\Permission;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class HomepageSettingRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return $this->user()?->can(Permission::SETTINGS_UPDATE->value) ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'hero_image' => ['nullable', 'image', 'max:5120'],
|
||||
'about_image' => ['nullable', 'image', 'max:5120'],
|
||||
'gallery_images' => ['nullable', 'array', 'max:10'],
|
||||
'gallery_images.*' => ['image', 'max:5120'],
|
||||
'gallery_images_remove' => ['nullable', 'array'],
|
||||
'gallery_images_remove.*' => ['integer'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function attributes(): array
|
||||
{
|
||||
return [
|
||||
'hero_image' => 'Foto Hero',
|
||||
'about_image' => 'Foto Tentang Kami',
|
||||
'gallery_images' => 'Foto Lookbook',
|
||||
'gallery_images.*' => 'Foto Lookbook',
|
||||
];
|
||||
}
|
||||
}
|
||||
35
app/Models/HomepageConfiguration.php
Normal file
35
app/Models/HomepageConfiguration.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Concerns\HasModuleMedia;
|
||||
use App\Models\Concerns\InteractsWithActivityLog;
|
||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Spatie\MediaLibrary\HasMedia;
|
||||
|
||||
#[Guarded(['id'])]
|
||||
class HomepageConfiguration extends Model implements HasMedia
|
||||
{
|
||||
use HasFactory;
|
||||
use HasModuleMedia;
|
||||
use InteractsWithActivityLog;
|
||||
|
||||
public static function mediaModuleName(): string
|
||||
{
|
||||
return 'homepage';
|
||||
}
|
||||
|
||||
public static function instance(): self
|
||||
{
|
||||
return static::query()->firstOrCreate(['id' => 1]);
|
||||
}
|
||||
|
||||
public function registerMediaCollections(): void
|
||||
{
|
||||
$this->addMediaCollection('hero_image')->singleFile();
|
||||
$this->addMediaCollection('about_image')->singleFile();
|
||||
$this->addMediaCollection('gallery')->singleFile();
|
||||
}
|
||||
}
|
||||
55
app/Services/System/Setting/HomepageSettingService.php
Normal file
55
app/Services/System/Setting/HomepageSettingService.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\System\Setting;
|
||||
|
||||
use App\Models\HomepageConfiguration;
|
||||
use App\Services\Media\MediaService;
|
||||
use App\Support\Media\MediaPresenter;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
|
||||
class HomepageSettingService
|
||||
{
|
||||
public function __construct(
|
||||
private readonly MediaService $mediaService,
|
||||
) {}
|
||||
|
||||
public function homepageData(): array
|
||||
{
|
||||
$configuration = HomepageConfiguration::instance();
|
||||
$configuration->load('media');
|
||||
|
||||
$heroImage = MediaPresenter::first($configuration, 'hero_image');
|
||||
$aboutImage = MediaPresenter::first($configuration, 'about_image');
|
||||
$galleryImages = MediaPresenter::collection($configuration, 'gallery');
|
||||
|
||||
return [
|
||||
'hero_image_url' => $heroImage['url'] ?? null,
|
||||
'about_image_url' => $aboutImage['url'] ?? null,
|
||||
'gallery_images' => $galleryImages,
|
||||
];
|
||||
}
|
||||
|
||||
public function updateHomepage(array $validated): void
|
||||
{
|
||||
$configuration = HomepageConfiguration::instance();
|
||||
|
||||
if (isset($validated['hero_image']) && $validated['hero_image'] instanceof UploadedFile) {
|
||||
$this->mediaService->replaceSingleFile($configuration, $validated['hero_image'], 'hero_image', 'hero-image');
|
||||
}
|
||||
|
||||
if (isset($validated['about_image']) && $validated['about_image'] instanceof UploadedFile) {
|
||||
$this->mediaService->replaceSingleFile($configuration, $validated['about_image'], 'about_image', 'about-image');
|
||||
}
|
||||
|
||||
if (isset($validated['gallery_images'])) {
|
||||
$this->mediaService->syncCollection(
|
||||
$configuration,
|
||||
'gallery',
|
||||
$validated['gallery_images'] ?? [],
|
||||
$validated['gallery_images_remove'] ?? [],
|
||||
10,
|
||||
'gallery',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
89
app/Settings/HomepageSettings.php
Normal file
89
app/Settings/HomepageSettings.php
Normal file
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace App\Settings;
|
||||
|
||||
use Spatie\LaravelSettings\Settings;
|
||||
|
||||
class HomepageSettings extends Settings
|
||||
{
|
||||
// Hero Section
|
||||
public string $hero_badge;
|
||||
|
||||
public string $hero_title_line1;
|
||||
|
||||
public string $hero_title_line2;
|
||||
|
||||
public string $hero_title_highlight;
|
||||
|
||||
public string $hero_description;
|
||||
|
||||
public string $hero_cta_primary_text;
|
||||
|
||||
public string $hero_cta_secondary_text;
|
||||
|
||||
public ?string $hero_image_url;
|
||||
|
||||
public string $hero_bg_text_left;
|
||||
|
||||
public string $hero_bg_text_right;
|
||||
|
||||
// Scroll Indicator
|
||||
public string $scroll_hashtag;
|
||||
|
||||
public string $scroll_tagline;
|
||||
|
||||
// Catalog Section
|
||||
public string $catalog_badge;
|
||||
|
||||
public string $catalog_title;
|
||||
|
||||
public string $catalog_description;
|
||||
|
||||
public string $catalog_search_placeholder;
|
||||
|
||||
// Gallery Section
|
||||
public string $gallery_badge;
|
||||
|
||||
public string $gallery_title;
|
||||
|
||||
public string $gallery_description;
|
||||
|
||||
public array $gallery_images;
|
||||
|
||||
// Order Guide Section
|
||||
public string $order_guide_badge;
|
||||
|
||||
public string $order_guide_title;
|
||||
|
||||
public string $order_guide_description;
|
||||
|
||||
public array $order_steps;
|
||||
|
||||
// About Section
|
||||
public string $about_badge;
|
||||
|
||||
public string $about_title;
|
||||
|
||||
public ?string $about_image_url;
|
||||
|
||||
public array $about_features;
|
||||
|
||||
// Contact Section
|
||||
public string $contact_badge;
|
||||
|
||||
public string $contact_title;
|
||||
|
||||
public string $contact_description;
|
||||
|
||||
public string $contact_form_title;
|
||||
|
||||
// Footer
|
||||
public string $footer_description;
|
||||
|
||||
public string $footer_copyright;
|
||||
|
||||
public static function group(): string
|
||||
{
|
||||
return 'homepage';
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('homepage_configurations', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('homepage_configurations');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
use Spatie\LaravelSettings\Migrations\SettingsBlueprint;
|
||||
use Spatie\LaravelSettings\Migrations\SettingsMigration;
|
||||
|
||||
return new class extends SettingsMigration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$this->migrator->inGroup('homepage', function (SettingsBlueprint $blueprint): void {
|
||||
// Hero Section
|
||||
$blueprint->add('hero_badge', 'Koleksi Segar 2026');
|
||||
$blueprint->add('hero_title_line1', 'Ekspresikan');
|
||||
$blueprint->add('hero_title_line2', 'Gaya');
|
||||
$blueprint->add('hero_title_highlight', 'Segar Anda');
|
||||
$blueprint->add('hero_description', 'Selamat datang di {app_name}. Temukan keanggunan motif batik modern dan setelan pakaian santai berkualitas premium. Dirancang khusus dengan bahan adem yang menyejukkan aktivitas harian Anda.');
|
||||
$blueprint->add('hero_cta_primary_text', 'Beli Sekarang');
|
||||
$blueprint->add('hero_cta_secondary_text', 'Tentang Kami');
|
||||
$blueprint->add('hero_image_url', 'https://images.unsplash.com/photo-1490481651871-ab68de25d43d?w=1000&auto=format&fit=crop&q=80');
|
||||
$blueprint->add('hero_bg_text_left', 'DST');
|
||||
$blueprint->add('hero_bg_text_right', 'Collection');
|
||||
|
||||
// Scroll Indicator
|
||||
$blueprint->add('scroll_hashtag', '#DSTCollection');
|
||||
$blueprint->add('scroll_tagline', 'Bahan Adem & Lembut');
|
||||
|
||||
// Catalog Section
|
||||
$blueprint->add('catalog_badge', 'Katalog Eksklusif');
|
||||
$blueprint->add('catalog_title', 'Koleksi Busana Pilihan');
|
||||
$blueprint->add('catalog_description', 'Gunakan kategori dan filter di bawah untuk menyesuaikan pencarian busana idaman Anda dengan mudah.');
|
||||
$blueprint->add('catalog_search_placeholder', 'Cari nama pakaian...');
|
||||
|
||||
// Deal Section
|
||||
$blueprint->add('deal_badge', 'Promo Terbatas');
|
||||
$blueprint->add('deal_title', 'Penawaran Bulan Ini');
|
||||
$blueprint->add('deal_description', 'Jangan lewatkan promosi batik dan daster eksklusif kami! Dapatkan potongan harga spesial up to 25% untuk varian daster pilihan dan setelan pakaian modern. Dapatkan kenyamanan ekstra dengan bahan menyejukkan sebelum masa promo habis!');
|
||||
$blueprint->add('deal_cta_text', 'Jelajahi Produk Diskon');
|
||||
$blueprint->add('deal_images', [
|
||||
'https://images.unsplash.com/photo-1595777457583-95e059d581b8?w=800&auto=format&fit=crop&q=80',
|
||||
'https://images.unsplash.com/photo-1572804013309-59a88b7e92f1?w=800&auto=format&fit=crop&q=80',
|
||||
'https://images.unsplash.com/photo-1515886657613-9f3515b0c78f?w=800&auto=format&fit=crop&q=80',
|
||||
'https://images.unsplash.com/photo-1539109136881-3be0616acf4b?w=800&auto=format&fit=crop&q=80',
|
||||
]);
|
||||
|
||||
// Order Guide Section
|
||||
$blueprint->add('order_guide_badge', 'Langkah Pemesanan');
|
||||
$blueprint->add('order_guide_title', 'Cara Melakukan Pemesanan');
|
||||
$blueprint->add('order_guide_description', 'Sistem pemesanan kami sangat mudah dan terhubung langsung via WhatsApp untuk pelayanan cepat dan personal.');
|
||||
$blueprint->add('order_steps', [
|
||||
[
|
||||
'title' => 'Pilih Produk',
|
||||
'description' => 'Jelajahi pakaian batik dan daster favorit Anda, lalu ketuk "Lihat Detail" untuk memeriksa ukuran.',
|
||||
],
|
||||
[
|
||||
'title' => 'Pilih Varian & Harga',
|
||||
'description' => 'Tentukan varian ukuran yang diinginkan dan pilih jenis harga (Eceran, Grosir, Agen, dll.).',
|
||||
],
|
||||
[
|
||||
'title' => 'Masukkan Keranjang',
|
||||
'description' => 'Masukkan ke Keranjang Belanja untuk menampung seluruh daftar pakaian yang ingin Anda beli.',
|
||||
],
|
||||
[
|
||||
'title' => 'Kirim ke WhatsApp',
|
||||
'description' => 'Klik tombol kirim pesanan, admin kami akan merespons rincian transfer bank dan pengiriman kurir.',
|
||||
],
|
||||
]);
|
||||
|
||||
// About Section
|
||||
$blueprint->add('about_badge', 'Tentang Kami');
|
||||
$blueprint->add('about_title', 'DST Collection');
|
||||
$blueprint->add('about_image_url', 'https://images.unsplash.com/photo-1595777457583-95e059d581b8?w=800&auto=format&fit=crop&q=80');
|
||||
$blueprint->add('about_features', [
|
||||
'Kain Rayon Super Tebal & Menyerap Keringat',
|
||||
'Motif Eksklusif & Tidak Pasaran',
|
||||
'Dukungan Penuh Layanan Admin Via WhatsApp',
|
||||
]);
|
||||
|
||||
// Contact Section
|
||||
$blueprint->add('contact_badge', 'Kontak Kami');
|
||||
$blueprint->add('contact_title', 'Ada Pertanyaan? Hubungi Kami');
|
||||
$blueprint->add('contact_description', 'Kami sangat senang mendengarkan pertanyaan Anda terkait spesifikasi produk, ketersediaan grosir, atau kemitraan. Hubungi tim admin kami melalui media di bawah.');
|
||||
$blueprint->add('contact_form_title', 'Kirim Pesan Cepat');
|
||||
|
||||
// Footer
|
||||
$blueprint->add('footer_description', 'Galeri resmi {app_name}. Pilihan busana lokal premium berpotongan modern dengan kenyamanan menyejukkan.');
|
||||
$blueprint->add('footer_copyright', '© 2026 {app_name} DST Collection. Hak Cipta Dilindungi.');
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Spatie\LaravelSettings\Migrations\SettingsBlueprint;
|
||||
use Spatie\LaravelSettings\Migrations\SettingsMigration;
|
||||
|
||||
return new class extends SettingsMigration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$this->migrator->inGroup('homepage', function (SettingsBlueprint $blueprint): void {
|
||||
// Delete old deal fields
|
||||
$blueprint->delete('deal_badge');
|
||||
$blueprint->delete('deal_title');
|
||||
$blueprint->delete('deal_description');
|
||||
$blueprint->delete('deal_cta_text');
|
||||
$blueprint->delete('deal_images');
|
||||
|
||||
// Add new gallery fields
|
||||
$blueprint->add('gallery_badge', 'Galeri Kami');
|
||||
$blueprint->add('gallery_title', 'Koleksi Lookbook');
|
||||
$blueprint->add('gallery_description', 'Intip koleksi lookbook kami untuk inspirasi gaya sehari-hari. Padu padan batik modern dan daster yang nyaman untuk berbagai suasana.');
|
||||
$blueprint->add('gallery_images', [
|
||||
'https://images.unsplash.com/photo-1595777457583-95e059d581b8?w=800&auto=format&fit=crop&q=80',
|
||||
'https://images.unsplash.com/photo-1572804013309-59a88b7e92f1?w=800&auto=format&fit=crop&q=80',
|
||||
'https://images.unsplash.com/photo-1515886657613-9f3515b0c78f?w=800&auto=format&fit=crop&q=80',
|
||||
'https://images.unsplash.com/photo-1539109136881-3be0616acf4b?w=800&auto=format&fit=crop&q=80',
|
||||
'https://images.unsplash.com/photo-1496747611176-843222e1e57c?w=800&auto=format&fit=crop&q=80',
|
||||
'https://images.unsplash.com/photo-1509631179647-0177331693ae?w=800&auto=format&fit=crop&q=80',
|
||||
]);
|
||||
});
|
||||
}
|
||||
};
|
||||
116
resources/js/components/admin/setting/HomepageSection.vue
Normal file
116
resources/js/components/admin/setting/HomepageSection.vue
Normal file
@ -0,0 +1,116 @@
|
||||
<script setup lang="ts">
|
||||
import { router } from '@inertiajs/vue3';
|
||||
import { Save } from '@lucide/vue';
|
||||
import { ref } from 'vue';
|
||||
import { toast } from 'vue-sonner';
|
||||
import ImageUploadField from '@/components/form/image-upload-field/ImageUploadField.vue';
|
||||
import MultipleImageUploadField from '@/components/form/image-upload-field/MultipleImageUploadField.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { createMediaUploadState } from '@/types/media';
|
||||
import type { HomepageSettingsData } from '@/types/setting';
|
||||
import type { MediaUploadState } from '@/types/media';
|
||||
|
||||
const props = defineProps<{
|
||||
data: HomepageSettingsData;
|
||||
}>();
|
||||
|
||||
const heroImage = ref<File | null>(null);
|
||||
const aboutImage = ref<File | null>(null);
|
||||
const galleryState = ref<MediaUploadState>(
|
||||
createMediaUploadState(props.data.gallery_images),
|
||||
);
|
||||
const isSubmitting = ref(false);
|
||||
|
||||
function submit() {
|
||||
isSubmitting.value = true;
|
||||
|
||||
const formData = new FormData();
|
||||
|
||||
if (heroImage.value) {
|
||||
formData.append('hero_image', heroImage.value);
|
||||
}
|
||||
|
||||
if (aboutImage.value) {
|
||||
formData.append('about_image', aboutImage.value);
|
||||
}
|
||||
|
||||
galleryState.value.newFiles.forEach((file) => {
|
||||
formData.append('gallery_images[]', file);
|
||||
});
|
||||
|
||||
galleryState.value.removeIds.forEach((id) => {
|
||||
formData.append('gallery_images_remove[]', String(id));
|
||||
});
|
||||
|
||||
router.put('/admin/system/setting/homepage', formData, {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
toast.success('Pengaturan homepage berhasil disimpan.');
|
||||
heroImage.value = null;
|
||||
aboutImage.value = null;
|
||||
},
|
||||
onError: () => {
|
||||
toast.error('Gagal menyimpan pengaturan homepage.');
|
||||
},
|
||||
onFinish: () => {
|
||||
isSubmitting.value = false;
|
||||
},
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<form @submit.prevent="submit">
|
||||
<div class="grid gap-4">
|
||||
|
||||
<!-- Hero Image -->
|
||||
<Card>
|
||||
<CardContent>
|
||||
<ImageUploadField
|
||||
id="hero_image"
|
||||
label="Foto Hero"
|
||||
description="Foto utama yang ditampilkan di bagian hero homepage."
|
||||
:current-url="props.data.hero_image_url"
|
||||
v-model="heroImage"
|
||||
preview-class="aspect-[3/4] max-w-xs"
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<!-- Gallery / Lookbook -->
|
||||
<Card>
|
||||
<CardContent>
|
||||
<MultipleImageUploadField
|
||||
id="gallery_images"
|
||||
label="Koleksi Lookbook"
|
||||
description="Foto-foto yang ditampilkan di galeri lookbook."
|
||||
:max-files="10"
|
||||
v-model="galleryState"
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<!-- About Image -->
|
||||
<Card>
|
||||
<CardContent>
|
||||
<ImageUploadField
|
||||
id="about_image"
|
||||
label="Foto Tentang Kami"
|
||||
description="Foto yang ditampilkan di bagian tentang kami."
|
||||
:current-url="props.data.about_image_url"
|
||||
v-model="aboutImage"
|
||||
preview-class="aspect-video max-w-md"
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<div class="flex justify-end">
|
||||
<Button type="submit" :disabled="isSubmitting">
|
||||
<Save class="size-4" />
|
||||
{{ isSubmitting ? 'Menyimpan...' : 'Simpan' }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { Settings2, Share2, ShoppingBag, Users } from '@lucide/vue';
|
||||
import { Home, Settings2, Share2, ShoppingBag, Users } from '@lucide/vue';
|
||||
import AdminLayout from '@/layouts/AdminLayout.vue';
|
||||
import { cn } from '@/lib/utils';
|
||||
import type { SettingSection } from '@/types/setting';
|
||||
@ -12,6 +12,7 @@ const navItems: Array<{
|
||||
icon: typeof Settings2;
|
||||
}> = [
|
||||
{ key: 'system', label: 'Sistem', icon: Settings2 },
|
||||
{ key: 'homepage', label: 'Homepage', icon: Home },
|
||||
{ key: 'social', label: 'Media Sosial', icon: Share2 },
|
||||
{ key: 'marketplace', label: 'Marketplace', icon: ShoppingBag },
|
||||
{ key: 'hr', label: 'HR / Pegawai', icon: Users },
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,12 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import { Head } from '@inertiajs/vue3';
|
||||
import { ref } from 'vue';
|
||||
import HomepageSection from '@/components/admin/setting/HomepageSection.vue';
|
||||
import HrSection from '@/components/admin/setting/HrSection.vue';
|
||||
import MarketplaceSection from '@/components/admin/setting/MarketplaceSection.vue';
|
||||
import SocialMediaSection from '@/components/admin/setting/SocialMediaSection.vue';
|
||||
import SystemSection from '@/components/admin/setting/SystemSection.vue';
|
||||
import SettingLayout from '@/layouts/SettingLayout.vue';
|
||||
import type {
|
||||
HomepageSettingsData,
|
||||
HrSettingsData,
|
||||
MarketplaceSettingsData,
|
||||
SettingSection,
|
||||
@ -19,6 +21,7 @@ defineProps<{
|
||||
socialMedia: SocialMediaSettingsData;
|
||||
marketplace: MarketplaceSettingsData;
|
||||
hr: HrSettingsData;
|
||||
homepage: HomepageSettingsData;
|
||||
}>();
|
||||
|
||||
const activeSection = ref<SettingSection>('system');
|
||||
@ -30,6 +33,7 @@ const activeSection = ref<SettingSection>('system');
|
||||
|
||||
<SettingLayout v-model:section="activeSection">
|
||||
<SystemSection v-if="activeSection === 'system'" :data="system" />
|
||||
<HomepageSection v-else-if="activeSection === 'homepage'" :data="homepage" />
|
||||
<SocialMediaSection v-else-if="activeSection === 'social'" :data="socialMedia" />
|
||||
<MarketplaceSection v-else-if="activeSection === 'marketplace'" :data="marketplace" />
|
||||
<HrSection v-else-if="activeSection === 'hr'" :data="hr" />
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
export type SettingSection = 'system' | 'social' | 'marketplace' | 'hr';
|
||||
export type SettingSection = 'system' | 'social' | 'marketplace' | 'hr' | 'homepage';
|
||||
|
||||
export type MarketplacePlatform = 'tiktok_shop' | 'shopee';
|
||||
|
||||
@ -53,3 +53,15 @@ export type HrSettingsData = {
|
||||
late_penalty_amount: number;
|
||||
absent_penalty_amount: number;
|
||||
};
|
||||
|
||||
export type MediaItem = {
|
||||
id: number;
|
||||
url: string;
|
||||
thumb_url: string;
|
||||
};
|
||||
|
||||
export type HomepageSettingsData = {
|
||||
hero_image_url: string | null;
|
||||
about_image_url: string | null;
|
||||
gallery_images: MediaItem[];
|
||||
};
|
||||
|
||||
@ -333,6 +333,10 @@
|
||||
Route::put('hr', [SettingController::class, 'updateHr'])
|
||||
->middleware('permission:'.Permission::SETTINGS_UPDATE->value)
|
||||
->name('hr.update');
|
||||
|
||||
Route::put('homepage', [SettingController::class, 'updateHomepage'])
|
||||
->middleware('permission:'.Permission::SETTINGS_UPDATE->value)
|
||||
->name('homepage.update');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user