Skip to content

Commit 71bf8f3

Browse files
authored
Merge pull request #27 from theafolayan/theafolayan/add-contact-management-resource
Add Filament resource for managing contacts
2 parents 02d2a1c + 1230a98 commit 71bf8f3

4 files changed

Lines changed: 198 additions & 0 deletions

File tree

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Filament\Resources;
6+
7+
use App\Enums\ContactStatus;
8+
use App\Filament\Resources\ContactResource\Pages\CreateContact;
9+
use App\Filament\Resources\ContactResource\Pages\EditContact;
10+
use App\Filament\Resources\ContactResource\Pages\ListContacts;
11+
use App\Models\Contact;
12+
use Filament\Forms;
13+
use Filament\Resources\Resource;
14+
use Filament\Schemas\Components\Grid;
15+
use Filament\Schemas\Components\Section;
16+
use Filament\Schemas\Schema;
17+
use Filament\Tables;
18+
use Filament\Tables\Filters\SelectFilter;
19+
use Filament\Tables\Table;
20+
use Illuminate\Support\Str;
21+
22+
class ContactResource extends Resource
23+
{
24+
protected static ?string $model = Contact::class;
25+
26+
protected static string|\UnitEnum|null $navigationGroup = 'Audience';
27+
28+
protected static string|\BackedEnum|null $navigationIcon = 'heroicon-m-users';
29+
30+
public static function form(Schema $schema): Schema
31+
{
32+
return $schema->components([
33+
Section::make('Details')
34+
->schema([
35+
Grid::make(2)->schema([
36+
Forms\Components\TextInput::make('email')
37+
->label('Email')
38+
->required()
39+
->email()
40+
->maxLength(255),
41+
Forms\Components\Select::make('status')
42+
->label('Status')
43+
->options(self::statusOptions())
44+
->default(ContactStatus::Active->value)
45+
->required(),
46+
Forms\Components\TextInput::make('first_name')
47+
->label('First name')
48+
->maxLength(255),
49+
Forms\Components\TextInput::make('last_name')
50+
->label('Last name')
51+
->maxLength(255),
52+
]),
53+
]),
54+
Section::make('Lists')
55+
->schema([
56+
Forms\Components\Select::make('lists')
57+
->label('Lists')
58+
->relationship('lists', 'name')
59+
->multiple()
60+
->preload()
61+
->searchable()
62+
->helperText('Assign the contact to one or more lists.'),
63+
])
64+
->collapsible()
65+
->collapsed(),
66+
Section::make('Attributes')
67+
->schema([
68+
Forms\Components\KeyValue::make('attributes')
69+
->label('Attributes')
70+
->helperText('Store additional metadata as key-value pairs.')
71+
->nullable()
72+
->columnSpanFull(),
73+
])
74+
->collapsible()
75+
->collapsed(),
76+
]);
77+
}
78+
79+
public static function table(Table $table): Table
80+
{
81+
return $table
82+
->columns([
83+
Tables\Columns\TextColumn::make('email')
84+
->label('Email')
85+
->sortable()
86+
->searchable(),
87+
Tables\Columns\TextColumn::make('first_name')
88+
->label('First name')
89+
->sortable()
90+
->toggleable(),
91+
Tables\Columns\TextColumn::make('last_name')
92+
->label('Last name')
93+
->sortable()
94+
->toggleable(),
95+
Tables\Columns\TextColumn::make('status')
96+
->label('Status')
97+
->badge()
98+
->formatStateUsing(static function (?ContactStatus $status): string {
99+
if ($status === null) {
100+
return '';
101+
}
102+
103+
return Str::title($status->value);
104+
}),
105+
Tables\Columns\TextColumn::make('lists_count')
106+
->label('Lists')
107+
->counts('lists')
108+
->badge(),
109+
Tables\Columns\TextColumn::make('created_at')
110+
->label('Created')
111+
->dateTime()
112+
->sortable()
113+
->toggleable(isToggledHiddenByDefault: true),
114+
Tables\Columns\TextColumn::make('updated_at')
115+
->label('Updated')
116+
->dateTime()
117+
->sortable()
118+
->toggleable(isToggledHiddenByDefault: true),
119+
])
120+
->filters([
121+
SelectFilter::make('status')
122+
->label('Status')
123+
->options(self::statusOptions()),
124+
]);
125+
}
126+
127+
public static function getPages(): array
128+
{
129+
return [
130+
'index' => ListContacts::route('/contacts'),
131+
'create' => CreateContact::route('/contacts/create'),
132+
'edit' => EditContact::route('/contacts/{record}/edit'),
133+
];
134+
}
135+
136+
/**
137+
* @return array<string, string>
138+
*/
139+
private static function statusOptions(): array
140+
{
141+
$options = [];
142+
143+
foreach (ContactStatus::cases() as $status) {
144+
$options[$status->value] = Str::title($status->value);
145+
}
146+
147+
return $options;
148+
}
149+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Filament\Resources\ContactResource\Pages;
6+
7+
use App\Filament\Resources\ContactResource;
8+
use App\Services\UsageTracker;
9+
use Filament\Resources\Pages\CreateRecord;
10+
11+
class CreateContact extends CreateRecord
12+
{
13+
protected static string $resource = ContactResource::class;
14+
15+
protected function afterCreate(): void
16+
{
17+
$workspace = currentWorkspace();
18+
19+
if ($workspace !== null) {
20+
app(UsageTracker::class)->recordContactsCreated($workspace);
21+
}
22+
}
23+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Filament\Resources\ContactResource\Pages;
6+
7+
use App\Filament\Resources\ContactResource;
8+
use Filament\Resources\Pages\EditRecord;
9+
10+
class EditContact extends EditRecord
11+
{
12+
protected static string $resource = ContactResource::class;
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Filament\Resources\ContactResource\Pages;
6+
7+
use App\Filament\Resources\ContactResource;
8+
use Filament\Resources\Pages\ListRecords;
9+
10+
class ListContacts extends ListRecords
11+
{
12+
protected static string $resource = ContactResource::class;
13+
}

0 commit comments

Comments
 (0)