diff --git a/app/Livewire/SocialAccounts/Index.php b/app/Livewire/SocialAccounts/Index.php
new file mode 100644
index 0000000..a58b1ff
--- /dev/null
+++ b/app/Livewire/SocialAccounts/Index.php
@@ -0,0 +1,91 @@
+ SocialAccount::orderBy('username')->get(),
+ 'networks' => SocialAccount::NETWORKS,
+ 'types' => SocialAccount::TYPES,
+ ]);
+ }
+
+ public function create(): void
+ {
+ $this->resetForm();
+ $this->showForm = true;
+ }
+
+ public function edit(int $id): void
+ {
+ $account = SocialAccount::findOrFail($id);
+ $this->editingId = $account->id;
+ $this->network = $account->network;
+ $this->username = $account->username;
+ $this->email = $account->email;
+ $this->password = $account->password;
+ $this->type = $account->type;
+ $this->showForm = true;
+ }
+
+ public function save(): void
+ {
+ $validated = $this->validate([
+ 'network' => ['required', 'string', 'in:' . implode(',', SocialAccount::NETWORKS)],
+ 'username' => ['required', 'string', 'max:255'],
+ 'email' => ['required', 'string', 'max:255'],
+ 'password' => ['required', 'string', 'max:255'],
+ 'type' => ['nullable', 'string', 'in:' . implode(',', SocialAccount::TYPES)],
+ ]);
+
+ SocialAccount::updateOrCreate(['id' => $this->editingId], $validated);
+
+ $this->resetForm();
+ $this->showForm = false;
+ }
+
+ public function delete(int $id): void
+ {
+ SocialAccount::findOrFail($id)->delete();
+ }
+
+ public function toggleReveal(int $id): void
+ {
+ $this->revealedId = $this->revealedId === $id ? null : $id;
+ }
+
+ public function resetForm(): void
+ {
+ $this->editingId = null;
+ $this->network = '';
+ $this->username = '';
+ $this->email = '';
+ $this->password = '';
+ $this->type = null;
+ $this->resetValidation();
+ }
+}
diff --git a/resources/views/livewire/social-accounts/index.blade.php b/resources/views/livewire/social-accounts/index.blade.php
new file mode 100644
index 0000000..11d8e01
--- /dev/null
+++ b/resources/views/livewire/social-accounts/index.blade.php
@@ -0,0 +1,96 @@
+
+
+
Social Accounts
+
+
+
+
+
+
+ | Network |
+ Username |
+ Email |
+ Password |
+ Type |
+ |
+
+
+
+ @foreach ($accounts as $account)
+
+ | {{ ucfirst($account->network) }} |
+ {{ $account->username }} |
+ {{ $account->email }} |
+
+ @if ($revealedId === $account->id)
+ {{ $account->password }}
+ @else
+ ••••••••
+ @endif
+
+ |
+ {{ $account->type ? ucfirst($account->type) : '—' }} |
+
+
+
+ |
+
+ @endforeach
+
+
+
+ @if ($showForm)
+
+
+
{{ $editingId ? 'Edit Account' : 'Add Account' }}
+
+
+
+
+ @error('network') {{ $message }} @enderror
+
+
+
+
+
+ @error('username') {{ $message }} @enderror
+
+
+
+
+
+ @error('email') {{ $message }} @enderror
+
+
+
+
+
+ @error('password') {{ $message }} @enderror
+
+
+
+
+
+ @error('type') {{ $message }} @enderror
+
+
+
+
+
+
+
+
+ @endif
+
diff --git a/routes/web.php b/routes/web.php
index 4520504..e8729ff 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -1,6 +1,7 @@
name('sites.index');
-
-// placeholder, replaced in Task 6
-Route::get('/social-accounts', SitesIndex::class)->name('social-accounts.index');
+Route::get('/social-accounts', SocialAccountsIndex::class)->name('social-accounts.index');
diff --git a/tests/Feature/Livewire/SocialAccountsTest.php b/tests/Feature/Livewire/SocialAccountsTest.php
new file mode 100644
index 0000000..d0451fc
--- /dev/null
+++ b/tests/Feature/Livewire/SocialAccountsTest.php
@@ -0,0 +1,67 @@
+create(['username' => 'example_user']);
+
+ $this->get(route('social-accounts.index'))
+ ->assertOk()
+ ->assertSee('example_user');
+});
+
+test('a new social account can be created', function () {
+ Livewire::test(Index::class)
+ ->set('network', 'twitter')
+ ->set('username', 'new_user')
+ ->set('email', 'new_user@example.com')
+ ->set('password', 'secret123')
+ ->set('type', 'post')
+ ->call('save');
+
+ expect(SocialAccount::where('username', 'new_user')->exists())->toBeTrue();
+});
+
+test('network, username, email, and password are required', function () {
+ Livewire::test(Index::class)
+ ->set('network', '')
+ ->set('username', '')
+ ->set('email', '')
+ ->set('password', '')
+ ->call('save')
+ ->assertHasErrors(['network', 'username', 'email', 'password']);
+});
+
+test('type can be left null', function () {
+ Livewire::test(Index::class)
+ ->set('network', 'reddit')
+ ->set('username', 'no_type_user')
+ ->set('email', 'no_type@example.com')
+ ->set('password', 'secret123')
+ ->set('type', null)
+ ->call('save');
+
+ $account = SocialAccount::where('username', 'no_type_user')->first();
+ expect($account->type)->toBeNull();
+});
+
+test('an existing account can be edited', function () {
+ $account = SocialAccount::factory()->create(['username' => 'old_name']);
+
+ Livewire::test(Index::class)
+ ->call('edit', $account->id)
+ ->set('username', 'new_name')
+ ->call('save');
+
+ expect($account->fresh()->username)->toBe('new_name');
+});
+
+test('an account can be deleted', function () {
+ $account = SocialAccount::factory()->create();
+
+ Livewire::test(Index::class)->call('delete', $account->id);
+
+ expect(SocialAccount::find($account->id))->toBeNull();
+});