F
Filament2mo ago
Wim

Custom view for Conversation with Messages

I have a conversation and a message model. I have the following relations as defined in the PDF. In a Filament resource called MessagesResource I want to create conversations and messages.
class MessageResource extends Resource {
protected static ?string $model = Conversation::class;
protected static ?string $tenantOwnershipRelationshipName = 'user';
protected static ?string $tenantRelationshipName = 'users';

public static function getEloquentQuery(): Builder {
return Conversation::query();
}

public static function form(Form $form): Form
{
return $form
->schema([
TextInput::make('subject'), //subject is part of conversation table

TextInput::make('message.organization_id'), //organization_id is part of message table

Select::make('message.sender_id') //sender_id is part of message table
->options(User::all()->pluck('name', 'id')->toArray())

Select::make('message.receiver_id') //receiver is part of message table
->options(User::all()->pluck('name', 'id')->toArray())

TextInput::make('message.content'), // message is part of message table
]);
}
class MessageResource extends Resource {
protected static ?string $model = Conversation::class;
protected static ?string $tenantOwnershipRelationshipName = 'user';
protected static ?string $tenantRelationshipName = 'users';

public static function getEloquentQuery(): Builder {
return Conversation::query();
}

public static function form(Form $form): Form
{
return $form
->schema([
TextInput::make('subject'), //subject is part of conversation table

TextInput::make('message.organization_id'), //organization_id is part of message table

Select::make('message.sender_id') //sender_id is part of message table
->options(User::all()->pluck('name', 'id')->toArray())

Select::make('message.receiver_id') //receiver is part of message table
->options(User::all()->pluck('name', 'id')->toArray())

TextInput::make('message.content'), // message is part of message table
]);
}
In the CreateMessage I do the following:
protected function handleRecordCreation(array $data): Model
{
$record = static::getModel()::create($data);
$record->messages()->create($data['message']);
return $record;
}
protected function handleRecordCreation(array $data): Model
{
$record = static::getModel()::create($data);
$record->messages()->create($data['message']);
return $record;
}
This works fine. Messages and conversations are created in my database and I display the conversations in my table. See screenshot. I would like have a view whereby I can see all messages from that conversation and also add a new reply. The view should open when the user clicks on a action called 'see messages' Any suggestions on how I can do this?
7 Replies
dissto
dissto2mo ago
The easiest and most straightforward is probably a relation manager 🤔
Wim
Wim2mo ago
It's more or less what I try to build yes.
krekas
krekas2mo ago
RepeatableEntry::make('messages')
->hiddenLabel()
->schema(fn () => [
Grid::make()
->schema([
TextEntry::make('sender.name')
->inlineLabel(),
TextEntry::make('created_at')
->inlineLabel()
->hiddenLabel()
->since()
->alignEnd(),
]),
TextEntry::make('content')
->hiddenLabel(),
])
->columnSpanFull(),
RepeatableEntry::make('messages')
->hiddenLabel()
->schema(fn () => [
Grid::make()
->schema([
TextEntry::make('sender.name')
->inlineLabel(),
TextEntry::make('created_at')
->inlineLabel()
->hiddenLabel()
->since()
->alignEnd(),
]),
TextEntry::make('content')
->hiddenLabel(),
])
->columnSpanFull(),
This is how messages are being shown The callback isn't needed anymore as it was a bug some time ago
Wim
Wim2mo ago
Thanks so much. I figured indeed it would indeed use a RepeatableEntry. I have an additional question if you don't mind: In the video you posted I see the reply button. I did that as follows:
TextEntry::make('Reply')
->hintAction(Action::make('openModal')
->button()
->label('Reply to this thread')
->form([
TextInput::make('content')
])
->action(function ($data, $record) {
// store into database
})),
TextEntry::make('Reply')
->hintAction(Action::make('openModal')
->button()
->label('Reply to this thread')
->form([
TextInput::make('content')
])
->action(function ($data, $record) {
// store into database
})),
Wim
Wim2mo ago
However it looks as follows. Is there a better way so that only the button is displayed? Preferably aligned to the left like in the video you shared?
No description
krekas
krekas2mo ago
You could buy it and see for yourself everything
public static function infolist(Infolist $infolist): Infolist
{
return $infolist
->schema([
RepeatableEntry::make('messages')
->hiddenLabel()
->schema(fn () => [
Grid::make()
->schema([
TextEntry::make('sender.name')
->inlineLabel(),
TextEntry::make('created_at')
->inlineLabel()
->hiddenLabel()
->since()
->alignEnd(),
]),
TextEntry::make('content')
->hiddenLabel(),
])
->columnSpanFull(),
Actions::make([
Action::make('reply')
->form([
Forms\Components\Textarea::make('content')
->required(),
])
->action(function (Topic $record, array $data): void {
$record->messages()->create([
'sender_id' => auth()->id(),
'content' => $data['content'],
]);

// Send notification to the user receiving the message
$receiver = (auth()->id() === $record['creator_id']) ? $record['receiver_id'] : $record['creator_id'];

Notification::make()
->title('New Reply To ' . $record->subject)
->sendToDatabase(User::find($receiver));
})
])
->columnSpanFull(),
]);
}
public static function infolist(Infolist $infolist): Infolist
{
return $infolist
->schema([
RepeatableEntry::make('messages')
->hiddenLabel()
->schema(fn () => [
Grid::make()
->schema([
TextEntry::make('sender.name')
->inlineLabel(),
TextEntry::make('created_at')
->inlineLabel()
->hiddenLabel()
->since()
->alignEnd(),
]),
TextEntry::make('content')
->hiddenLabel(),
])
->columnSpanFull(),
Actions::make([
Action::make('reply')
->form([
Forms\Components\Textarea::make('content')
->required(),
])
->action(function (Topic $record, array $data): void {
$record->messages()->create([
'sender_id' => auth()->id(),
'content' => $data['content'],
]);

// Send notification to the user receiving the message
$receiver = (auth()->id() === $record['creator_id']) ? $record['receiver_id'] : $record['creator_id'];

Notification::make()
->title('New Reply To ' . $record->subject)
->sendToDatabase(User::find($receiver));
})
])
->columnSpanFull(),
]);
}
This is how infolist is