diff --git a/app/Filament/Pages/Settings/ManageGeneralSettings.php b/app/Filament/Pages/Settings/ManageGeneralSettings.php index fb11870..bac0ac9 100644 --- a/app/Filament/Pages/Settings/ManageGeneralSettings.php +++ b/app/Filament/Pages/Settings/ManageGeneralSettings.php @@ -54,6 +54,19 @@ public function form(Schema $schema): Schema ->required() ->maxLength(255), + TextInput::make('site_email') + ->label('Email Website') + ->placeholder('diskominfo@purwakartakab.go.id') + ->email() + ->required() + ->maxLength(255), + + TextInput::make('site_phone') + ->label('Nomor Telepon') + ->placeholder('(0264) 200222') + ->required() + ->maxLength(255), + RichEditor::make('about_us') ->label('Tentang Kami') ->placeholder('...') diff --git a/app/Filament/Resources/Manage/Contacts/ContactResource.php b/app/Filament/Resources/Manage/Contacts/ContactResource.php new file mode 100644 index 0000000..320599d --- /dev/null +++ b/app/Filament/Resources/Manage/Contacts/ContactResource.php @@ -0,0 +1,199 @@ +count(); + } + + public static function form(Schema $schema): Schema + { + return $schema + ->components([ + // Form usually not needed as we use View/Reply + ]); + } + + public static function infolist(Schema $schema): Schema + { + return $schema + ->schema([ + Section::make('Informasi Pengirim') + ->schema([ + Grid::make(4) + ->schema([ + TextEntry::make('name') + ->label('Nama'), + + TextEntry::make('email') + ->label('Email'), + + TextEntry::make('subject') + ->label('Subyek'), + + TextEntry::make('created_at') + ->label('Diterima pada') + ->date('l, d F Y H:i'), + ]), + ]) + ->columnSpanFull(), + + Section::make('Pesan') + ->schema([ + TextEntry::make('message') + ->label('Isi Pesan') + ->columnSpanFull(), + ]) + ->columnSpanFull(), + + Section::make('Balasan') + ->schema([ + TextEntry::make('repliedBy.name') + ->label('Dibalas Oleh') + ->placeholder('Belum dibalas'), + + TextEntry::make('replied_at') + ->label('Dibalas pada') + ->date('l, d F Y H:i') + ->placeholder('Belum dibalas'), + + TextEntry::make('reply_message') + ->label('Pesan Balasan') + ->placeholder('Belum dibalas'), + ]) + ->columnSpanFull() + ->visible(fn ($record) => $record->replied_at !== null), + ]) + ->columns(2); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + TextColumn::make('name') + ->label('Nama') + ->searchable(), + + TextColumn::make('email') + ->label('Email') + ->searchable(), + + TextColumn::make('subject') + ->label('Subyek') + ->limit(30), + + IconColumn::make('replied_at') + ->label('Dibalas') + ->boolean() + ->getStateUsing(fn ($record) => $record->replied_at !== null), + + TextColumn::make('repliedBy.name') + ->label('Dibalas Oleh') + ->badge() + ->placeholder('Belum dibalas') + ->sortable(), + + TextColumn::make('created_at') + ->label('Diterima pada') + ->date('l, d F Y H:i') + ->sortable(), + ]) + ->filters([ + // + ]) + ->recordActions([ + ViewAction::make() + ->label('Lihat'), + + Action::make('reply') + ->label('Balas') + ->icon(Heroicon::ChatBubbleLeftRight) + ->color('success') + ->modalHeading('Balas Pesan Kontak') + ->modalDescription('Pesan balasan tidak bisa diubah setelah dikirim.') + ->schema([ + Textarea::make('reply_message') + ->label('Pesan Balasan') + ->placeholder(fn ($record) => "Halo {$record->name}, ...") + ->required() + ->rows(5), + ]) + ->action(function (Contact $record, array $data) { + Mail::to($record->email)->send(new ContactReplyMail($record, $data['reply_message'])); + + $record->update([ + 'reply_message' => $data['reply_message'], + 'replied_at' => now(), + 'replied_by' => auth()->id(), + ]); + + Notification::make() + ->title('Balasan terkirim') + ->success() + ->send(); + }) + ->visible(fn ($record) => $record->replied_at === null), + + DeleteAction::make() + ->label('Hapus'), + ]) + ->toolbarActions([ + BulkActionGroup::make([ + ...DefaultBulkActions::make('Kontak'), + ]), + ]) + ->emptyStateIcon(Heroicon::Envelope) + ->emptyStateDescription('Belum ada kontak atau pesan masuk.') + ->defaultSort('created_at', 'desc') + ->deferFilters(false) + ->reorderable('sort_order'); + } + + public static function getPages(): array + { + return [ + 'index' => ManageContacts::route('/'), + ]; + } +} diff --git a/app/Filament/Resources/Manage/Contacts/Pages/ManageContacts.php b/app/Filament/Resources/Manage/Contacts/Pages/ManageContacts.php new file mode 100644 index 0000000..f429ca3 --- /dev/null +++ b/app/Filament/Resources/Manage/Contacts/Pages/ManageContacts.php @@ -0,0 +1,11 @@ +contact->subject ?? 'Pesan Kontak'), + ); + } + + /** + * Get the message content definition. + */ + public function content(): Content + { + $settings = app(GeneralSettings::class); + $logoPath = $settings->site_logo + ? storage_path('app/public/'.$settings->site_logo) + : public_path('assets/img/logo/icon-with-text.png'); + + return new Content( + view: 'emails.contact-reply', + with: [ + 'name' => $this->contact->name, + 'replyMessage' => $this->replyMessage, + 'site_name' => $settings->site_name, + 'logoPath' => $logoPath, + ], + ); + } + + /** + * Get the attachments for the message. + * + * @return array + */ + public function attachments(): array + { + return []; + } +} diff --git a/app/Models/Contact.php b/app/Models/Contact.php new file mode 100644 index 0000000..c00fac8 --- /dev/null +++ b/app/Models/Contact.php @@ -0,0 +1,24 @@ +belongsTo(User::class, 'replied_by'); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index d2a9a48..8a3cf69 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -57,6 +57,11 @@ public function company(): HasOne return $this->hasOne(Company::class); } + public function contacts(): HasMany + { + return $this->hasMany(Contact::class, 'replied_by'); + } + public function news(): HasMany { return $this->hasMany(News::class, 'author_id'); diff --git a/database/migrations/2026_01_05_153123_create_contacts_table.php b/database/migrations/2026_01_05_153123_create_contacts_table.php new file mode 100644 index 0000000..3d49b07 --- /dev/null +++ b/database/migrations/2026_01_05_153123_create_contacts_table.php @@ -0,0 +1,37 @@ +id(); + $table->string('name', 100); + $table->string('email', 254); + $table->string('subject')->nullable(); + $table->text('message'); + $table->text('reply_message')->nullable(); + $table->timestamp('replied_at')->nullable(); + $table->foreignIdFor(User::class, 'replied_by')->nullable()->constrained()->cascadeOnDelete(); + $table->timestamp('created_at')->useCurrent(); + $table->timestamp('updated_at')->nullable()->useCurrentOnUpdate(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('contacts'); + } +}; diff --git a/resources/views/emails/contact-reply.blade.php b/resources/views/emails/contact-reply.blade.php new file mode 100644 index 0000000..8b54783 --- /dev/null +++ b/resources/views/emails/contact-reply.blade.php @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + +
+ + {{ $site_name }} + + +

+ Sistem Informasi Media Komunikasi. +

+
+ + + + + + + +
+

Hello {{ $name }},

+

{!! nl2br(e($replyMessage)) !!}

+

----
Regards
+ {{ $site_name }}

+
+ + + + + + +
+

© {{ date('Y') }} + {{ $site_name }}. Seluruh Hak Cipta + Dilindungi. +

+
+
+
+ + +