From f0dbea1af500f905faca136a2e8184059602fca7 Mon Sep 17 00:00:00 2001
From: gbanyan
Date: Tue, 10 Feb 2026 15:31:29 +0800
Subject: [PATCH] Add Line ID field to member lifecycle
---
app/Console/Commands/ImportMembers.php | 2 ++
.../Controllers/AdminMemberController.php | 15 ++++++++--
.../Controllers/MemberDashboardController.php | 4 ++-
.../PublicMemberRegistrationController.php | 2 ++
app/Http/Requests/StoreMemberRequest.php | 1 +
app/Http/Requests/UpdateMemberRequest.php | 1 +
app/Models/Member.php | 1 +
...10_120000_add_line_id_to_members_table.php | 28 +++++++++++++++++++
.../views/admin/members/create.blade.php | 18 +++++++++++-
resources/views/admin/members/edit.blade.php | 18 +++++++++++-
.../views/admin/members/import.blade.php | 1 +
resources/views/admin/members/index.blade.php | 6 ++--
resources/views/admin/members/show.blade.php | 9 ++++++
.../views/member/create-profile.blade.php | 7 +++++
resources/views/member/dashboard.blade.php | 9 ++++++
resources/views/register/member.blade.php | 7 +++++
tests/Feature/MemberRegistrationTest.php | 3 ++
tests/Traits/CreatesMemberData.php | 1 +
18 files changed, 124 insertions(+), 9 deletions(-)
create mode 100644 database/migrations/2026_02_10_120000_add_line_id_to_members_table.php
diff --git a/app/Console/Commands/ImportMembers.php b/app/Console/Commands/ImportMembers.php
index 818e48d..966900b 100644
--- a/app/Console/Commands/ImportMembers.php
+++ b/app/Console/Commands/ImportMembers.php
@@ -85,6 +85,7 @@ class ImportMembers extends Command
$memberNumber = isset($indexes['member_number']) ? trim($row[$indexes['member_number']] ?? '') : '';
$nationalId = isset($indexes['national_id']) ? trim($row[$indexes['national_id']] ?? '') : '';
$phone = trim($row[$indexes['phone']] ?? '');
+ $lineId = isset($indexes['line_id']) ? trim($row[$indexes['line_id']] ?? '') : '';
$phoneHome = isset($indexes['phone_home']) ? trim($row[$indexes['phone_home']] ?? '') : '';
$phoneFax = isset($indexes['phone_fax']) ? trim($row[$indexes['phone_fax']] ?? '') : '';
$birthDate = isset($indexes['birth_date']) ? trim($row[$indexes['birth_date']] ?? '') : '';
@@ -125,6 +126,7 @@ class ImportMembers extends Command
'email' => $email,
'national_id' => $nationalId !== '' ? $nationalId : null,
'phone' => $phone !== '' ? $phone : null,
+ 'line_id' => $lineId !== '' ? $lineId : null,
'phone_home' => $phoneHome !== '' ? $phoneHome : null,
'phone_fax' => $phoneFax !== '' ? $phoneFax : null,
'birth_date' => $birthDate !== '' ? $birthDate : null,
diff --git a/app/Http/Controllers/AdminMemberController.php b/app/Http/Controllers/AdminMemberController.php
index a104b01..a4ef94e 100644
--- a/app/Http/Controllers/AdminMemberController.php
+++ b/app/Http/Controllers/AdminMemberController.php
@@ -17,12 +17,13 @@ class AdminMemberController extends Controller
{
$query = Member::query()->with('user');
- // Text search (name, email, phone, national ID)
+ // Text search (name, email, phone, Line ID, national ID)
if ($search = $request->string('search')->toString()) {
$query->where(function ($q) use ($search) {
$q->where('full_name', 'like', "%{$search}%")
->orWhere('email', 'like', "%{$search}%")
- ->orWhere('phone', 'like', "%{$search}%");
+ ->orWhere('phone', 'like', "%{$search}%")
+ ->orWhere('line_id', 'like', "%{$search}%");
// Search by national ID hash if provided
if (!empty($search)) {
@@ -256,7 +257,13 @@ class AdminMemberController extends Controller
if ($search = $request->string('search')->toString()) {
$query->where(function ($q) use ($search) {
$q->where('full_name', 'like', "%{$search}%")
- ->orWhere('email', 'like', "%{$search}%");
+ ->orWhere('email', 'like', "%{$search}%")
+ ->orWhere('phone', 'like', "%{$search}%")
+ ->orWhere('line_id', 'like', "%{$search}%");
+
+ if (!empty($search)) {
+ $q->orWhere('national_id_hash', hash('sha256', $search));
+ }
});
}
@@ -276,6 +283,7 @@ class AdminMemberController extends Controller
'Full Name',
'Email',
'Phone',
+ 'Line ID',
'Address Line 1',
'Address Line 2',
'City',
@@ -297,6 +305,7 @@ class AdminMemberController extends Controller
$member->full_name,
$member->email,
$member->phone,
+ $member->line_id,
$member->address_line_1,
$member->address_line_2,
$member->city,
diff --git a/app/Http/Controllers/MemberDashboardController.php b/app/Http/Controllers/MemberDashboardController.php
index f63cee2..b5961de 100644
--- a/app/Http/Controllers/MemberDashboardController.php
+++ b/app/Http/Controllers/MemberDashboardController.php
@@ -54,6 +54,7 @@ class MemberDashboardController extends Controller
$validated = $request->validate([
'full_name' => ['required', 'string', 'max:255'],
'phone' => ['nullable', 'string', 'max:20'],
+ 'line_id' => ['nullable', 'string', 'max:100'],
'national_id' => ['nullable', 'string', 'max:20'],
'address_line_1' => ['nullable', 'string', 'max:255'],
'address_line_2' => ['nullable', 'string', 'max:255'],
@@ -69,6 +70,7 @@ class MemberDashboardController extends Controller
'full_name' => $validated['full_name'],
'email' => $user->email,
'phone' => $validated['phone'] ?? null,
+ 'line_id' => $validated['line_id'] ?? null,
'national_id' => $validated['national_id'] ?? null,
'address_line_1' => $validated['address_line_1'] ?? null,
'address_line_2' => $validated['address_line_2'] ?? null,
@@ -88,4 +90,4 @@ class MemberDashboardController extends Controller
return redirect()->route('member.dashboard')
->with('status', __('Profile completed! Please submit your membership payment.'));
}
-}
\ No newline at end of file
+}
diff --git a/app/Http/Controllers/PublicMemberRegistrationController.php b/app/Http/Controllers/PublicMemberRegistrationController.php
index df07e97..09255a3 100644
--- a/app/Http/Controllers/PublicMemberRegistrationController.php
+++ b/app/Http/Controllers/PublicMemberRegistrationController.php
@@ -32,6 +32,7 @@ class PublicMemberRegistrationController extends Controller
'email' => ['required', 'string', 'email', 'max:255', 'unique:users,email', 'unique:members,email'],
'password' => ['required', 'confirmed', Password::defaults()],
'phone' => ['nullable', 'string', 'max:20'],
+ 'line_id' => ['nullable', 'string', 'max:100'],
'national_id' => ['nullable', 'string', 'max:20'],
'address_line_1' => ['nullable', 'string', 'max:255'],
'address_line_2' => ['nullable', 'string', 'max:255'],
@@ -57,6 +58,7 @@ class PublicMemberRegistrationController extends Controller
'full_name' => $validated['full_name'],
'email' => $validated['email'],
'phone' => $validated['phone'] ?? null,
+ 'line_id' => $validated['line_id'] ?? null,
'national_id' => $validated['national_id'] ?? null,
'address_line_1' => $validated['address_line_1'] ?? null,
'address_line_2' => $validated['address_line_2'] ?? null,
diff --git a/app/Http/Requests/StoreMemberRequest.php b/app/Http/Requests/StoreMemberRequest.php
index 6dfc775..96a077f 100644
--- a/app/Http/Requests/StoreMemberRequest.php
+++ b/app/Http/Requests/StoreMemberRequest.php
@@ -27,6 +27,7 @@ class StoreMemberRequest extends FormRequest
'email' => ['required', 'email', 'max:255', 'unique:users,email'],
'national_id' => ['nullable', 'string', 'max:50'],
'phone' => ['nullable', 'string', 'max:50'],
+ 'line_id' => ['nullable', 'string', 'max:100'],
'phone_home' => ['nullable', 'string', 'max:50'],
'phone_fax' => ['nullable', 'string', 'max:50'],
'birth_date' => ['nullable', 'date'],
diff --git a/app/Http/Requests/UpdateMemberRequest.php b/app/Http/Requests/UpdateMemberRequest.php
index bd9c3e5..2f4bb7a 100644
--- a/app/Http/Requests/UpdateMemberRequest.php
+++ b/app/Http/Requests/UpdateMemberRequest.php
@@ -33,6 +33,7 @@ class UpdateMemberRequest extends FormRequest
'email' => ['required', 'email', 'max:255'],
'national_id' => ['nullable', 'string', 'max:50'],
'phone' => ['nullable', 'string', 'max:50'],
+ 'line_id' => ['nullable', 'string', 'max:100'],
'phone_home' => ['nullable', 'string', 'max:50'],
'phone_fax' => ['nullable', 'string', 'max:50'],
'birth_date' => ['nullable', 'date'],
diff --git a/app/Models/Member.php b/app/Models/Member.php
index 9e0cb4e..19eb0f6 100644
--- a/app/Models/Member.php
+++ b/app/Models/Member.php
@@ -42,6 +42,7 @@ class Member extends Model
'full_name',
'email',
'phone',
+ 'line_id',
'phone_home',
'phone_fax',
'address_line_1',
diff --git a/database/migrations/2026_02_10_120000_add_line_id_to_members_table.php b/database/migrations/2026_02_10_120000_add_line_id_to_members_table.php
new file mode 100644
index 0000000..ef8ff0f
--- /dev/null
+++ b/database/migrations/2026_02_10_120000_add_line_id_to_members_table.php
@@ -0,0 +1,28 @@
+string('line_id', 100)->nullable();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('members', function (Blueprint $table) {
+ $table->dropColumn('line_id');
+ });
+ }
+};
diff --git a/resources/views/admin/members/create.blade.php b/resources/views/admin/members/create.blade.php
index 994d274..1e63eb2 100644
--- a/resources/views/admin/members/create.blade.php
+++ b/resources/views/admin/members/create.blade.php
@@ -169,7 +169,7 @@
-
+
+
+
+
+ @error('line_id')
+
{{ $message }}
+ @enderror
+
+
-
+
+
+
+
+ @error('line_id')
+
{{ $message }}
+ @enderror
+
+
+
+
+ Line ID
+
+
+ {{ $member->line_id ?? __('Not set') }}
+
+
+
室內電話/傳真
diff --git a/resources/views/member/create-profile.blade.php b/resources/views/member/create-profile.blade.php
index c690544..f13be99 100644
--- a/resources/views/member/create-profile.blade.php
+++ b/resources/views/member/create-profile.blade.php
@@ -34,6 +34,13 @@
+
+
+
+
+
+
+
diff --git a/resources/views/member/dashboard.blade.php b/resources/views/member/dashboard.blade.php
index 6e53b96..d8b9298 100644
--- a/resources/views/member/dashboard.blade.php
+++ b/resources/views/member/dashboard.blade.php
@@ -92,6 +92,15 @@
+
+
+ {{ __('Line ID') }}
+
+
+ {{ $member->line_id ?: __('Not set') }}
+
+
+
{{ __('Membership Type') }}
diff --git a/resources/views/register/member.blade.php b/resources/views/register/member.blade.php
index dc7aeda..11fd5bc 100644
--- a/resources/views/register/member.blade.php
+++ b/resources/views/register/member.blade.php
@@ -50,6 +50,13 @@
+
+
+
+
+
+
+
diff --git a/tests/Feature/MemberRegistrationTest.php b/tests/Feature/MemberRegistrationTest.php
index 25ee02e..323f666 100644
--- a/tests/Feature/MemberRegistrationTest.php
+++ b/tests/Feature/MemberRegistrationTest.php
@@ -41,6 +41,7 @@ class MemberRegistrationTest extends TestCase
'password' => 'Password123!',
'password_confirmation' => 'Password123!',
'phone' => '0912345678',
+ 'line_id' => 'john_doe_line',
'address_line_1' => '123 Test St',
'city' => 'Taipei',
'postal_code' => '100',
@@ -62,6 +63,7 @@ class MemberRegistrationTest extends TestCase
'full_name' => 'John Doe',
'email' => 'john@example.com',
'phone' => '0912345678',
+ 'line_id' => 'john_doe_line',
'membership_status' => Member::STATUS_PENDING,
]);
}
@@ -256,6 +258,7 @@ class MemberRegistrationTest extends TestCase
$member = Member::where('email', 'john@example.com')->first();
$this->assertNull($member->phone);
+ $this->assertNull($member->line_id);
$this->assertNull($member->address_line_1);
}
}
diff --git a/tests/Traits/CreatesMemberData.php b/tests/Traits/CreatesMemberData.php
index d5462d3..d79de08 100644
--- a/tests/Traits/CreatesMemberData.php
+++ b/tests/Traits/CreatesMemberData.php
@@ -132,6 +132,7 @@ trait CreatesMemberData
'password' => 'Password123!',
'password_confirmation' => 'Password123!',
'phone' => '0912345678',
+ 'line_id' => 'line.member.test',
'national_id' => 'A123456789',
'address_line_1' => '123 Test Street',
'address_line_2' => '',