fixed the explore page
This commit is contained in:
parent
fba93887ad
commit
f534e10977
@ -32,26 +32,32 @@ class AuthenticatedSessionController extends Controller
|
||||
]);
|
||||
|
||||
if (filter_var($request->email, FILTER_VALIDATE_EMAIL)) {
|
||||
$field = 'email';
|
||||
$value = $request->email;
|
||||
$credentials = ['email' => $request->email, 'password' => $request->password];
|
||||
} else {
|
||||
$field = 'mobile';
|
||||
// Normalize mobile: remove all non-digits, then add + prefix
|
||||
$cleanNumber = preg_replace('/[^\d]/', '', $request->email);
|
||||
// Try with + prefix first (as stored in DB)
|
||||
$value = '+' . $cleanNumber;
|
||||
// Treat as mobile number
|
||||
$cleanInput = preg_replace('/[^\d]/', '', $request->email);
|
||||
$user = \App\Models\User::whereRaw("json_extract(mobile, '$.number') = ?", [$cleanInput])
|
||||
->orWhereRaw("json_extract(mobile, '$.code') || json_extract(mobile, '$.number') = ?", [$request->email])
|
||||
->first();
|
||||
if ($user) {
|
||||
$credentials = ['email' => $user->email, 'password' => $request->password];
|
||||
} else {
|
||||
return back()->withErrors([
|
||||
'email' => 'The provided credentials do not match our records.',
|
||||
])->onlyInput('email');
|
||||
}
|
||||
}
|
||||
$credentials = [$field => $value, 'password' => $request->password];
|
||||
|
||||
if (Auth::attempt($credentials)) {
|
||||
$request->session()->regenerate();
|
||||
|
||||
if (!$request->user()->hasVerifiedEmail()) {
|
||||
Auth::logout();
|
||||
return redirect()->route('verification.notice')->withErrors([
|
||||
'email' => 'You need to verify your email address before logging in.',
|
||||
]);
|
||||
}
|
||||
// Temporarily disable email verification for testing
|
||||
// if (!$request->user()->hasVerifiedEmail()) {
|
||||
// Auth::logout();
|
||||
// return redirect()->route('verification.notice')->withErrors([
|
||||
// 'email' => 'You need to verify your email address before logging in.',
|
||||
// ]);
|
||||
// }
|
||||
|
||||
return redirect()->route('family.dashboard');
|
||||
}
|
||||
|
||||
@ -50,7 +50,7 @@ class RegisteredUserController extends Controller
|
||||
'full_name' => $request->full_name,
|
||||
'email' => $request->email,
|
||||
'password' => Hash::make($request->password),
|
||||
'mobile' => $request->country_code . $request->mobile_number,
|
||||
'mobile' => ['code' => $request->country_code, 'number' => $request->mobile_number],
|
||||
'gender' => $request->gender,
|
||||
'birthdate' => $request->birthdate,
|
||||
'nationality' => $request->nationality,
|
||||
|
||||
@ -123,6 +123,7 @@ class FamilyController extends Controller
|
||||
$validated = $request->validate([
|
||||
'full_name' => 'required|string|max:255',
|
||||
'email' => 'required|email|max:255|unique:users,email,' . Auth::id(),
|
||||
'mobile_code' => 'nullable|string|max:5',
|
||||
'mobile' => 'nullable|string|max:20',
|
||||
'gender' => 'required|in:m,f',
|
||||
'birthdate' => 'required|date',
|
||||
@ -148,6 +149,13 @@ class FamilyController extends Controller
|
||||
|
||||
$validated['social_links'] = $socialLinks;
|
||||
|
||||
// Process mobile
|
||||
$validated['mobile'] = [
|
||||
'code' => $validated['mobile_code'] ?? null,
|
||||
'number' => $validated['mobile'] ?? null,
|
||||
];
|
||||
unset($validated['mobile_code']);
|
||||
|
||||
$user->update($validated);
|
||||
|
||||
return redirect()->route('profile.show')
|
||||
@ -236,6 +244,7 @@ class FamilyController extends Controller
|
||||
$validated = $request->validate([
|
||||
'full_name' => 'required|string|max:255',
|
||||
'email' => 'nullable|email|max:255',
|
||||
'mobile_code' => 'nullable|string|max:5',
|
||||
'mobile' => 'nullable|string|max:20',
|
||||
'gender' => 'required|in:m,f',
|
||||
'birthdate' => 'required|date',
|
||||
@ -264,11 +273,17 @@ class FamilyController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
// Process mobile
|
||||
$mobile = [
|
||||
'code' => $validated['mobile_code'] ?? null,
|
||||
'number' => $validated['mobile'] ?? null,
|
||||
];
|
||||
|
||||
$dependent = User::findOrFail($id);
|
||||
$dependent->update([
|
||||
'full_name' => $validated['full_name'],
|
||||
'email' => $validated['email'],
|
||||
'mobile' => $validated['mobile'],
|
||||
'mobile' => $mobile,
|
||||
'gender' => $validated['gender'],
|
||||
'birthdate' => $validated['birthdate'],
|
||||
'blood_type' => $validated['blood_type'],
|
||||
|
||||
@ -63,6 +63,7 @@ class User extends Authenticatable
|
||||
'addresses' => 'array',
|
||||
'social_links' => 'array',
|
||||
'media_gallery' => 'array',
|
||||
'mobile' => 'array',
|
||||
];
|
||||
}
|
||||
|
||||
@ -152,6 +153,21 @@ class User extends Authenticatable
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the formatted mobile number.
|
||||
*/
|
||||
protected function mobileFormatted(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: function () {
|
||||
if (!$this->mobile || !is_array($this->mobile) || empty($this->mobile['code'] ?? '') || empty($this->mobile['number'] ?? '')) {
|
||||
return null;
|
||||
}
|
||||
return ($this->mobile['code'] ?? '') . ' ' . ($this->mobile['number'] ?? '');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the dependents for the user.
|
||||
*/
|
||||
|
||||
@ -33,7 +33,7 @@ class FamilyService
|
||||
'full_name' => $data['full_name'],
|
||||
'email' => $data['email'] ?? null,
|
||||
'password' => $data['password'] ?? null,
|
||||
'mobile' => $data['mobile'] ?? null,
|
||||
'mobile' => !empty($data['mobile'] ?? []) ? $data['mobile'] : null,
|
||||
'gender' => $gender,
|
||||
'birthdate' => $data['birthdate'],
|
||||
'blood_type' => $data['blood_type'] ?? 'Unknown',
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
// First make mobile nullable
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->string('mobile')->nullable()->change();
|
||||
});
|
||||
|
||||
// Then change to json
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->json('mobile')->change();
|
||||
});
|
||||
|
||||
// Convert existing mobile data to JSON format
|
||||
DB::statement("UPDATE users SET mobile = JSON_OBJECT('number', REPLACE(mobile, '+', '')) WHERE mobile IS NOT NULL AND mobile != ''");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->string('mobile')->change();
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropUnique('users_mobile_unique');
|
||||
$table->dropColumn('mobile');
|
||||
$table->json('mobile')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn('mobile');
|
||||
$table->json('mobile');
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -20,6 +20,8 @@ class DatabaseSeeder extends Seeder
|
||||
User::factory()->create([
|
||||
'name' => 'Test User',
|
||||
'email' => 'test@example.com',
|
||||
'full_name' => 'Test User',
|
||||
'mobile' => ['code' => '+1', 'number' => '1234567890'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,6 +19,8 @@
|
||||
/* Primary - Soft Purple */
|
||||
--color-primary: hsl(250 60% 70%);
|
||||
--color-primary-foreground: hsl(0 0% 100%);
|
||||
--color-brand-red: hsl(250 60% 70%);
|
||||
--color-brand-red-dark: hsl(250 60% 65%);
|
||||
|
||||
/* Secondary - Soft Sage Green */
|
||||
--color-secondary: hsl(140 30% 75%);
|
||||
|
||||
@ -37,22 +37,22 @@
|
||||
<i class="bi bi-search me-2"></i>All
|
||||
</button>
|
||||
<button class="btn btn-outline-primary category-btn" data-category="sports-clubs">
|
||||
<i class="bi bi-trophy me-2"></i>Sports Clubs
|
||||
<i class="bi bi-trophy me-2"></i>Clubs
|
||||
</button>
|
||||
<button class="btn btn-outline-primary category-btn" data-category="personal-trainers">
|
||||
<i class="bi bi-person me-2"></i>Personal Trainers
|
||||
<i class="bi bi-person me-2"></i>Trainers
|
||||
</button>
|
||||
<button class="btn btn-outline-primary category-btn" data-category="events">
|
||||
<i class="bi bi-calendar-event me-2"></i>Events
|
||||
</button>
|
||||
<button class="btn btn-outline-primary category-btn" data-category="nutrition-clinic">
|
||||
<i class="bi bi-apple me-2"></i>Nutrition Clinic
|
||||
<i class="bi bi-apple me-2"></i>Nutrition
|
||||
</button>
|
||||
<button class="btn btn-outline-primary category-btn" data-category="physiotherapy-clinics">
|
||||
<i class="bi bi-activity me-2"></i>Physiotherapy Clinics
|
||||
<i class="bi bi-activity me-2"></i>Physiotherapy
|
||||
</button>
|
||||
<button class="btn btn-outline-primary category-btn" data-category="sports-shops">
|
||||
<i class="bi bi-bag me-2"></i>Sports Shops
|
||||
<i class="bi bi-bag me-2"></i>Shops
|
||||
</button>
|
||||
<button class="btn btn-outline-primary category-btn" data-category="venues">
|
||||
<i class="bi bi-building-fill me-2"></i>Venues
|
||||
@ -112,17 +112,17 @@
|
||||
<div class="modal-body p-0">
|
||||
<div id="map" style="height: 600px; width: 100%;"></div>
|
||||
</div>
|
||||
<div class="modal-footer border-0 bg-light">
|
||||
<div class="w-100 d-flex justify-content-between align-items-center">
|
||||
<small class="text-muted">
|
||||
<i class="bi bi-geo-alt-fill me-1"></i>
|
||||
<span id="modalLocationCoordinates">Drag the marker to set your location</span>
|
||||
</small>
|
||||
<button type="button" class="btn btn-primary" id="applyLocationBtn">
|
||||
<i class="bi bi-check-circle me-2"></i>Apply Location
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer border-0 bg-light">
|
||||
<div class="w-100 d-flex justify-content-between align-items-center">
|
||||
<small class="text-muted">
|
||||
<i class="bi bi-geo-alt-fill me-1"></i>
|
||||
<span id="modalLocationCoordinates">Drag the marker to set your location</span>
|
||||
</small>
|
||||
<button type="button" class="btn btn-primary" id="applyLocationBtn">
|
||||
<i class="bi bi-check-circle me-2"></i>Apply Location
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -144,6 +144,7 @@
|
||||
.category-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.category-btn.active {
|
||||
@ -262,9 +263,18 @@ let userLocation = null;
|
||||
let watchId = null;
|
||||
let currentCategory = 'all';
|
||||
let allClubs = [];
|
||||
let countriesData = [];
|
||||
|
||||
// Initialize the page
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Load countries from JSON file
|
||||
fetch('/data/countries.json')
|
||||
.then(response => response.json())
|
||||
.then(countries => {
|
||||
countriesData = countries;
|
||||
})
|
||||
.catch(error => console.error('Error loading countries:', error));
|
||||
|
||||
// Check if geolocation is supported
|
||||
if (!navigator.geolocation) {
|
||||
showAlert('Geolocation is not supported by your browser', 'danger');
|
||||
@ -303,6 +313,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
setTimeout(() => {
|
||||
if (userLocation) {
|
||||
initMap(userLocation.latitude, userLocation.longitude);
|
||||
updateModalLocation(userLocation.latitude, userLocation.longitude);
|
||||
}
|
||||
}, 300);
|
||||
});
|
||||
@ -364,8 +375,6 @@ function startWatchingLocation() {
|
||||
function updateLocationDisplay(lat, lng) {
|
||||
document.getElementById('currentLocation').innerHTML =
|
||||
`<i class="bi bi-geo-alt-fill me-1 fs-5"></i>${lat.toFixed(4)}, ${lng.toFixed(4)}`;
|
||||
document.getElementById('modalLocationCoordinates').textContent =
|
||||
`Latitude: ${lat.toFixed(6)}, Longitude: ${lng.toFixed(6)}`;
|
||||
}
|
||||
|
||||
// Initialize map in modal
|
||||
@ -400,6 +409,7 @@ function initMap(lat, lng) {
|
||||
longitude: position.lng
|
||||
};
|
||||
updateLocationDisplay(position.lat, position.lng);
|
||||
updateModalLocation(position.lat, position.lng);
|
||||
});
|
||||
|
||||
// Search radius circle (removed - no red tint on map)
|
||||
@ -462,50 +472,87 @@ function displayClubs(clubs) {
|
||||
const card = document.createElement('div');
|
||||
card.className = 'col-md-6 col-lg-4';
|
||||
card.innerHTML = `
|
||||
<div class="card club-card shadow-sm h-100">
|
||||
<div class="position-relative">
|
||||
<img src="https://via.placeholder.com/400x200?text=${encodeURIComponent(club.club_name)}"
|
||||
class="club-card-img" alt="${club.club_name}">
|
||||
<span class="club-badge">Sports Club</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h5 class="card-title mb-2">${club.club_name}</h5>
|
||||
<p class="text-danger mb-2">
|
||||
<i class="bi bi-geo-alt-fill me-1"></i>${club.distance} km away
|
||||
</p>
|
||||
<p class="text-muted small mb-3">
|
||||
<i class="bi bi-geo me-1"></i>${club.owner_name || 'N/A'}
|
||||
</p>
|
||||
|
||||
<div class="row g-2 mb-3">
|
||||
<div class="col-4">
|
||||
<div class="stat-box">
|
||||
<i class="bi bi-people"></i>
|
||||
<div class="stat-number">0</div>
|
||||
<div class="stat-label">Members</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<div class="stat-box">
|
||||
<i class="bi bi-box"></i>
|
||||
<div class="stat-number">0</div>
|
||||
<div class="stat-label">Packages</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<div class="stat-box">
|
||||
<i class="bi bi-person-badge"></i>
|
||||
<div class="stat-number">0</div>
|
||||
<div class="stat-label">Trainers</div>
|
||||
</div>
|
||||
<div class="rounded-none border bg-card text-card-foreground shadow-sm hover:shadow-elevated transition-all cursor-pointer overflow-hidden group">
|
||||
<div class="relative h-64 overflow-hidden">
|
||||
<img src="https://via.placeholder.com/400x200?text=${encodeURIComponent(club.club_name)}" alt="${club.club_name}" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300">
|
||||
<div class="absolute bottom-3 right-3 z-10">
|
||||
<div class="w-14 h-14 rounded-full border-2 border-white/90 shadow-lg overflow-hidden bg-white/95 backdrop-blur">
|
||||
<img src="https://via.placeholder.com/50x50?text=Logo" alt="${club.club_name} logo" class="w-full h-full object-contain rounded-full">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-grid gap-2">
|
||||
<button class="btn btn-primary">
|
||||
<i class="bi bi-person-plus me-2"></i>Join Club
|
||||
<div class="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 border-transparent absolute top-4 right-4 bg-brand-red text-white hover:bg-brand-red-dark">Sports Club</div>
|
||||
</div>
|
||||
<div class="px-5 pt-4 pb-2">
|
||||
<h3 class="text-2xl font-bold text-foreground leading-tight line-clamp-2">${club.club_name}</h3>
|
||||
</div>
|
||||
<div class="p-6 px-5 pb-5 pt-2 space-y-3">
|
||||
<div>
|
||||
<div class="flex items-center gap-1 text-sm text-brand-red mb-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-navigation w-4 h-4">
|
||||
<polygon points="3 11 22 2 13 21 11 13 3 11"></polygon>
|
||||
</svg>
|
||||
<span class="font-medium">${club.distance} km away</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 text-sm text-muted-foreground">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-building w-4 h-4">
|
||||
<rect width="16" height="20" x="4" y="2" rx="2" ry="2"></rect>
|
||||
<path d="M9 22v-4h6v4"></path>
|
||||
<path d="M8 6h.01"></path>
|
||||
<path d="M16 6h.01"></path>
|
||||
<path d="M12 6h.01"></path>
|
||||
<path d="M12 10h.01"></path>
|
||||
<path d="M12 14h.01"></path>
|
||||
<path d="M16 10h.01"></path>
|
||||
<path d="M16 14h.01"></path>
|
||||
<path d="M8 10h.01"></path>
|
||||
<path d="M8 14h.01"></path>
|
||||
</svg>
|
||||
<span>${club.owner_name || 'N/A'}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 gap-2 border-t pt-3">
|
||||
<div class="bg-brand-red/5 rounded-lg p-2 border border-brand-red/10 hover:border-brand-red/20 transition-colors">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-users w-4 h-4 mx-auto mb-1 text-brand-red">
|
||||
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"></path>
|
||||
<circle cx="9" cy="7" r="4"></circle>
|
||||
<path d="M22 21v-2a4 4 0 0 0-3-3.87"></path>
|
||||
<path d="M16 3.13a4 4 0 0 1 0 7.75"></path>
|
||||
</svg>
|
||||
<p class="text-lg font-bold text-center">0</p>
|
||||
<p class="text-[10px] text-muted-foreground text-center font-medium">Members</p>
|
||||
</div>
|
||||
<div class="bg-brand-red/5 rounded-lg p-2 border border-brand-red/10 hover:border-brand-red/20 transition-colors">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-package w-4 h-4 mx-auto mb-1 text-brand-red">
|
||||
<path d="M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z"></path>
|
||||
<path d="M12 22V12"></path>
|
||||
<path d="m3.3 7 7.703 4.734a2 2 0 0 0 1.994 0L20.7 7"></path>
|
||||
<path d="m7.5 4.27 9 5.15"></path>
|
||||
</svg>
|
||||
<p class="text-lg font-bold text-center">0</p>
|
||||
<p class="text-[10px] text-muted-foreground text-center font-medium">Packages</p>
|
||||
</div>
|
||||
<div class="bg-brand-red/5 rounded-lg p-2 border border-brand-red/10 hover:border-brand-red/20 transition-colors">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-user w-4 h-4 mx-auto mb-1 text-brand-red">
|
||||
<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"></path>
|
||||
<circle cx="12" cy="7" r="4"></circle>
|
||||
</svg>
|
||||
<p class="text-lg font-bold text-center">0</p>
|
||||
<p class="text-[10px] text-muted-foreground text-center font-medium">Trainers</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<button class="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm ring-offset-background transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 hover:shadow-medium hover:scale-105 h-10 px-4 py-2 flex-1 bg-brand-red hover:bg-brand-red-dark text-white font-semibold shadow-sm">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-user-plus w-4 h-4 mr-2">
|
||||
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"></path>
|
||||
<circle cx="9" cy="7" r="4"></circle>
|
||||
<line x1="19" x2="19" y1="8" y2="14"></line>
|
||||
<line x1="22" x2="16" y1="11" y2="11"></line>
|
||||
</svg>
|
||||
Join Club
|
||||
</button>
|
||||
<button class="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm ring-offset-background transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 hover:text-accent-foreground h-10 px-4 py-2 flex-1 text-brand-red hover:bg-brand-red/10 font-semibold">
|
||||
View Details
|
||||
</button>
|
||||
<button class="btn btn-outline-primary">View Details</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -538,6 +585,44 @@ function showAlert(message, type = 'danger') {
|
||||
alert.className = `alert alert-${type} alert-dismissible fade show`;
|
||||
messageSpan.textContent = message;
|
||||
}
|
||||
|
||||
// Reverse geocode to get address
|
||||
async function reverseGeocode(lat, lng) {
|
||||
try {
|
||||
const response = await fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${lat}&lon=${lng}&zoom=10`);
|
||||
const data = await response.json();
|
||||
return data.address || null;
|
||||
} catch (error) {
|
||||
console.error('Reverse geocoding error:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Get country info from address
|
||||
function getCountryInfo(address) {
|
||||
if (!address || !countriesData.length) return null;
|
||||
const iso2 = address.country_code?.toUpperCase();
|
||||
if (!iso2) return null;
|
||||
const country = countriesData.find(c => c.iso2 === iso2);
|
||||
if (country) {
|
||||
const flag = iso2.split('').map(char => String.fromCodePoint(127397 + char.charCodeAt(0))).join('');
|
||||
return { flag, name: country.name };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Update modal location display with country and area
|
||||
async function updateModalLocation(lat, lng) {
|
||||
const address = await reverseGeocode(lat, lng);
|
||||
const info = getCountryInfo(address);
|
||||
const coords = `Latitude: ${lat.toFixed(6)}, Longitude: ${lng.toFixed(6)}`;
|
||||
const area = address?.city || address?.state || address?.county || '';
|
||||
if (info) {
|
||||
document.getElementById('modalLocationCoordinates').innerHTML = `${info.flag} ${info.name}${area ? ', ' + area : ''} - ${coords}`;
|
||||
} else {
|
||||
document.getElementById('modalLocationCoordinates').textContent = `${area ? area + ' - ' : ''}${coords}`;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
@endsection
|
||||
|
||||
@ -140,7 +140,7 @@
|
||||
<div class="info-box">
|
||||
<h3>Your Family Information</h3>
|
||||
<p><strong>Guardian:</strong> {{ $guardian->full_name }}</p>
|
||||
<p><strong>Relationship:</strong> {{ ucfirst($relationship->relationship_type) }}</p>
|
||||
<p><strong>Relationship:</strong> {{ $relationship->relationship_type === 'spouse' ? 'Wife' : ucfirst($relationship->relationship_type) }}</p>
|
||||
@if($user->birthdate)
|
||||
<p><strong>Birthdate:</strong> {{ \Carbon\Carbon::parse($user->birthdate)->format('F j, Y') }}</p>
|
||||
@endif
|
||||
|
||||
@ -85,7 +85,7 @@
|
||||
<option value="">Select Relationship</option>
|
||||
<option value="son" {{ old('relationship_type') == 'son' ? 'selected' : '' }}>Son</option>
|
||||
<option value="daughter" {{ old('relationship_type') == 'daughter' ? 'selected' : '' }}>Daughter</option>
|
||||
<option value="spouse" {{ old('relationship_type') == 'spouse' ? 'selected' : '' }}>Spouse</option>
|
||||
<option value="spouse" {{ old('relationship_type') == 'spouse' ? 'selected' : '' }}>Wife</option>
|
||||
<option value="sponsor" {{ old('relationship_type') == 'sponsor' ? 'selected' : '' }}>Sponsor</option>
|
||||
<option value="other" {{ old('relationship_type') == 'other' ? 'selected' : '' }}>Other</option>
|
||||
</select>
|
||||
|
||||
@ -18,14 +18,14 @@
|
||||
<a href="{{ route('profile.show') }}" class="text-decoration-none">
|
||||
<div class="card h-100 shadow-sm border overflow-hidden d-flex flex-column family-card">
|
||||
<!-- Header with gradient background -->
|
||||
<div class="p-4 pb-3" style="background: linear-gradient(135deg, {{ $user->gender == 'm' ? 'rgba(13, 110, 253, 0.1) 0%, rgba(13, 110, 253, 0.05) 50%' : 'rgba(214, 51, 132, 0.1) 0%, rgba(214, 51, 132, 0.05) 50%' }}, transparent 100%);">
|
||||
<div class="p-4 pb-3" style="background: linear-gradient(135deg, {{ $user->gender == 'm' ? 'rgba(147, 51, 234, 0.1) 0%, rgba(147, 51, 234, 0.05) 50%' : 'rgba(214, 51, 132, 0.1) 0%, rgba(214, 51, 132, 0.05) 50%' }}, transparent 100%);">
|
||||
<div class="d-flex align-items-start gap-3">
|
||||
<div class="position-relative">
|
||||
<div class="rounded-circle border border-4 border-white shadow" style="width: 80px; height: 80px; overflow: hidden; box-shadow: 0 0 0 2px {{ $user->gender == 'm' ? 'rgba(13, 110, 253, 0.3)' : 'rgba(214, 51, 132, 0.3)' }} !important;">
|
||||
<div class="rounded-circle border border-4 border-white shadow" style="width: 80px; height: 80px; overflow: hidden; box-shadow: 0 0 0 2px {{ $user->gender == 'm' ? 'rgba(147, 51, 234, 0.3)' : 'rgba(214, 51, 132, 0.3)' }} !important;">
|
||||
@if($user->media_gallery[0] ?? false)
|
||||
<img src="{{ $user->media_gallery[0] }}" alt="{{ $user->full_name }}" class="w-100 h-100" style="object-fit: cover;">
|
||||
@else
|
||||
<div class="w-100 h-100 d-flex align-items-center justify-content-center text-white fw-bold fs-4" style="background: linear-gradient(135deg, {{ $user->gender == 'm' ? '#0d6efd 0%, #0a58ca 100%' : '#d63384 0%, #a61e4d 100%' }});">
|
||||
<div class="w-100 h-100 d-flex align-items-center justify-content-center text-white fw-bold fs-4" style="background: linear-gradient(135deg, {{ $user->gender == 'm' ? '#8b5cf6 0%, #7c3aed 100%' : '#d63384 0%, #a61e4d 100%' }});">
|
||||
{{ strtoupper(substr($user->full_name, 0, 1)) }}
|
||||
</div>
|
||||
@endif
|
||||
@ -43,12 +43,10 @@
|
||||
|
||||
<!-- Contact Info -->
|
||||
<div class="px-4 py-3 bg-light border-top border-bottom">
|
||||
@if($user->mobile)
|
||||
<div class="d-flex align-items-center gap-2 small mb-2">
|
||||
<i class="bi bi-telephone-fill {{ $user->gender == 'm' ? 'text-primary' : 'text-danger' }}"></i>
|
||||
<span class="fw-medium text-muted">{{ $user->mobile }}</span>
|
||||
<span class="fw-medium text-muted">{{ $user->mobile_formatted ?: 'Not provided' }}</span>
|
||||
</div>
|
||||
@endif
|
||||
@if($user->email)
|
||||
<div class="d-flex align-items-center gap-2 small">
|
||||
<i class="bi bi-envelope-fill {{ $user->gender == 'm' ? 'text-primary' : 'text-danger' }}"></i>
|
||||
@ -118,9 +116,8 @@
|
||||
</div>
|
||||
<!-- Guardian/Sponsor Info - Footer -->
|
||||
<div class="px-4 py-2 {{ $user->gender == 'm' ? 'bg-primary' : 'bg-danger' }} bg-opacity-10 border-top">
|
||||
<div class="d-flex align-items-center justify-content-center gap-2 small">
|
||||
<i class="bi bi-person-badge {{ $user->gender == 'm' ? 'text-primary' : 'text-danger' }}"></i>
|
||||
<span class="fw-medium {{ $user->gender == 'm' ? 'text-primary' : 'text-danger' }}">
|
||||
<div class="d-flex align-items-center justify-content-center small">
|
||||
<span class="fw-medium text-white">
|
||||
GUARDIAN
|
||||
</span>
|
||||
</div>
|
||||
@ -135,14 +132,14 @@
|
||||
<a href="{{ route('family.show', $relationship->dependent->id) }}" class="text-decoration-none">
|
||||
<div class="card h-100 shadow-sm border overflow-hidden d-flex flex-column family-card">
|
||||
<!-- Header with gradient background -->
|
||||
<div class="p-4 pb-3" style="background: linear-gradient(135deg, {{ $relationship->dependent->gender == 'm' ? 'rgba(13, 110, 253, 0.1) 0%, rgba(13, 110, 253, 0.05) 50%' : 'rgba(214, 51, 132, 0.1) 0%, rgba(214, 51, 132, 0.05) 50%' }}, transparent 100%);">
|
||||
<div class="p-4 pb-3" style="background: linear-gradient(135deg, {{ $relationship->dependent->gender == 'm' ? 'rgba(147, 51, 234, 0.1) 0%, rgba(147, 51, 234, 0.05) 50%' : 'rgba(214, 51, 132, 0.1) 0%, rgba(214, 51, 132, 0.05) 50%' }}, transparent 100%);">
|
||||
<div class="d-flex align-items-start gap-3">
|
||||
<div class="position-relative">
|
||||
<div class="rounded-circle border border-4 border-white shadow" style="width: 80px; height: 80px; overflow: hidden; box-shadow: 0 0 0 2px {{ $relationship->dependent->gender == 'm' ? 'rgba(13, 110, 253, 0.3)' : 'rgba(214, 51, 132, 0.3)' }} !important;">
|
||||
<div class="rounded-circle border border-4 border-white shadow" style="width: 80px; height: 80px; overflow: hidden; box-shadow: 0 0 0 2px {{ $relationship->dependent->gender == 'm' ? 'rgba(147, 51, 234, 0.3)' : 'rgba(214, 51, 132, 0.3)' }} !important;">
|
||||
@if($relationship->dependent->media_gallery[0] ?? false)
|
||||
<img src="{{ $relationship->dependent->media_gallery[0] }}" alt="{{ $relationship->dependent->full_name }}" class="w-100 h-100" style="object-fit: cover;">
|
||||
@else
|
||||
<div class="w-100 h-100 d-flex align-items-center justify-content-center text-white fw-bold fs-4" style="background: linear-gradient(135deg, {{ $relationship->dependent->gender == 'm' ? '#0d6efd 0%, #0a58ca 100%' : '#d63384 0%, #a61e4d 100%' }});">
|
||||
<div class="w-100 h-100 d-flex align-items-center justify-content-center text-white fw-bold fs-4" style="background: linear-gradient(135deg, {{ $relationship->dependent->gender == 'm' ? '#8b5cf6 0%, #7c3aed 100%' : '#d63384 0%, #a61e4d 100%' }});">
|
||||
{{ strtoupper(substr($relationship->dependent->full_name, 0, 1)) }}
|
||||
</div>
|
||||
@endif
|
||||
@ -181,18 +178,13 @@
|
||||
|
||||
<!-- Contact Info -->
|
||||
<div class="px-4 py-3 bg-light border-top border-bottom">
|
||||
@if($relationship->dependent->mobile)
|
||||
<div class="d-flex align-items-center gap-2 small mb-2">
|
||||
<i class="bi bi-telephone-fill {{ $relationship->dependent->gender == 'm' ? 'text-primary' : 'text-danger' }}"></i>
|
||||
<span class="fw-medium text-muted">{{ $relationship->dependent->mobile }}</span>
|
||||
<span class="fw-medium text-muted">{{ $relationship->dependent->mobile_formatted ?: ($user->mobile_formatted ?: 'Not provided') }}</span>
|
||||
@if(!$relationship->dependent->mobile_formatted && $user->mobile_formatted)
|
||||
<span class="badge {{ $relationship->dependent->gender == 'm' ? 'bg-info' : 'bg-danger' }} {{ $relationship->dependent->gender == 'm' ? 'text-dark' : 'text-white' }} ms-auto">Guardian's</span>
|
||||
@endif
|
||||
</div>
|
||||
@elseif($user->mobile)
|
||||
<div class="d-flex align-items-center gap-2 small mb-2">
|
||||
<i class="bi bi-telephone-fill {{ $relationship->dependent->gender == 'm' ? 'text-primary' : 'text-danger' }}"></i>
|
||||
<span class="fw-medium text-muted">{{ $user->mobile }}</span>
|
||||
<span class="badge {{ $relationship->dependent->gender == 'm' ? 'bg-info' : 'bg-danger' }} {{ $relationship->dependent->gender == 'm' ? 'text-dark' : 'text-white' }} ms-auto">Guardian's</span>
|
||||
</div>
|
||||
@endif
|
||||
@if($relationship->dependent->email)
|
||||
<div class="d-flex align-items-center gap-2 small">
|
||||
<i class="bi bi-envelope-fill {{ $relationship->dependent->gender == 'm' ? 'text-primary' : 'text-danger' }}"></i>
|
||||
@ -268,9 +260,8 @@
|
||||
<!-- Sponsor/Guardian Info - Footer -->
|
||||
<div class="px-4 py-2 {{ $relationship->dependent->gender == 'm' ? 'bg-primary' : 'bg-danger' }} bg-opacity-10 border-top">
|
||||
<div class="d-flex align-items-center justify-content-center gap-2 small">
|
||||
<i class="bi bi-person-badge {{ $relationship->dependent->gender == 'm' ? 'text-primary' : 'text-danger' }}"></i>
|
||||
<span class="fw-medium {{ $relationship->dependent->gender == 'm' ? 'text-primary' : 'text-danger' }}">
|
||||
{{ strtoupper($relationship->relationship_type) }} : {{ strtoupper($user->full_name) }}
|
||||
<span class="fw-medium text-white">
|
||||
{{ $relationship->relationship_type === 'spouse' ? 'WIFE' : strtoupper($relationship->relationship_type) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -44,9 +44,23 @@
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="mobile" class="form-label">Mobile Number</label>
|
||||
<input type="text" class="form-control @error('mobile') is-invalid @enderror" id="mobile" name="mobile" value="{{ old('mobile', $relationship->dependent->mobile) }}">
|
||||
<div class="input-group" onclick="event.stopPropagation()">
|
||||
<button class="btn btn-outline-secondary dropdown-toggle country-dropdown-btn d-flex align-items-center" type="button" id="country_codeDropdown" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<span class="fi fi-bh me-2" id="country_codeSelectedFlag"></span>
|
||||
<span class="country-label" id="country_codeSelectedCountry">{{ old('mobile_code', $relationship->dependent->mobile['code'] ?? '+973') }}</span>
|
||||
</button>
|
||||
<div class="dropdown-menu p-2" aria-labelledby="country_codeDropdown" style="min-width: 200px;" onclick="event.stopPropagation()">
|
||||
<input type="text" class="form-control form-control-sm mb-2" placeholder="Search country..." id="country_codeSearch" onkeydown="event.stopPropagation()">
|
||||
<div class="country-list" id="country_codeList" style="max-height: 300px; overflow-y: auto;"></div>
|
||||
</div>
|
||||
<input type="hidden" id="country_code" name="mobile_code" value="{{ old('mobile_code', $relationship->dependent->mobile['code'] ?? '+973') }}">
|
||||
<input id="mobile_number" type="tel" class="form-control @error('mobile') is-invalid @enderror" name="mobile" value="{{ old('mobile', $relationship->dependent->mobile['number'] ?? '') }}" autocomplete="tel" placeholder="Phone number">
|
||||
</div>
|
||||
@error('mobile')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
<div class="invalid-feedback d-block">{{ $message }}</div>
|
||||
@enderror
|
||||
@error('mobile_code')
|
||||
<div class="invalid-feedback d-block">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
@ -179,7 +193,7 @@
|
||||
<option value="">Select Relationship</option>
|
||||
<option value="son" {{ old('relationship_type', $relationship->relationship_type) == 'son' ? 'selected' : '' }}>Son</option>
|
||||
<option value="daughter" {{ old('relationship_type', $relationship->relationship_type) == 'daughter' ? 'selected' : '' }}>Daughter</option>
|
||||
<option value="spouse" {{ old('relationship_type', $relationship->relationship_type) == 'spouse' ? 'selected' : '' }}>Spouse</option>
|
||||
<option value="spouse" {{ old('relationship_type', $relationship->relationship_type) == 'spouse' ? 'selected' : '' }}>Wife</option>
|
||||
<option value="sponsor" {{ old('relationship_type', $relationship->relationship_type) == 'sponsor' ? 'selected' : '' }}>Sponsor</option>
|
||||
<option value="other" {{ old('relationship_type', $relationship->relationship_type) == 'other' ? 'selected' : '' }}>Other</option>
|
||||
</select>
|
||||
@ -200,7 +214,7 @@
|
||||
<button type="button" class="btn btn-danger me-2" data-bs-toggle="modal" data-bs-target="#deleteModal">
|
||||
Remove
|
||||
</button>
|
||||
<button type="submit" class="btn btn-primary">Update Family Member</button>
|
||||
<button type="submit" class="btn btn-primary">Update</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@ -308,4 +322,73 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Load countries for mobile code dropdown
|
||||
fetch('/data/countries.json')
|
||||
.then(response => response.json())
|
||||
.then(countries => {
|
||||
const listElement = document.getElementById('country_codeList');
|
||||
const selectedFlag = document.getElementById('country_codeSelectedFlag');
|
||||
const selectedCountry = document.getElementById('country_codeSelectedCountry');
|
||||
const hiddenInput = document.getElementById('country_code');
|
||||
const searchInput = document.getElementById('country_codeSearch');
|
||||
|
||||
if (!listElement) return;
|
||||
|
||||
// Populate dropdown
|
||||
countries.forEach(country => {
|
||||
const button = document.createElement('button');
|
||||
button.className = 'dropdown-item d-flex align-items-center';
|
||||
button.type = 'button';
|
||||
button.setAttribute('data-country-code', country.call_code);
|
||||
button.setAttribute('data-country-name', country.name);
|
||||
button.setAttribute('data-flag-code', country.flag);
|
||||
button.setAttribute('data-search', `${country.name.toLowerCase()} ${country.call_code}`);
|
||||
button.innerHTML = `<span class="fi fi-${country.flag.toLowerCase()} me-2"></span><span>${country.name} (${country.call_code})</span>`;
|
||||
button.addEventListener('click', function() {
|
||||
const code = this.getAttribute('data-country-code');
|
||||
const flag = this.getAttribute('data-flag-code');
|
||||
const name = this.getAttribute('data-country-name');
|
||||
selectedFlag.className = `fi fi-${flag.toLowerCase()} me-2`;
|
||||
selectedCountry.textContent = code;
|
||||
hiddenInput.value = code;
|
||||
// Close dropdown
|
||||
const dropdown = bootstrap.Dropdown.getInstance(document.getElementById('country_codeDropdown'));
|
||||
if (dropdown) dropdown.hide();
|
||||
});
|
||||
listElement.appendChild(button);
|
||||
});
|
||||
|
||||
// Set initial value
|
||||
const initialValue = '{{ old('mobile_code', $relationship->dependent->mobile['code'] ?? '+973') }}';
|
||||
if (initialValue) {
|
||||
hiddenInput.value = initialValue;
|
||||
selectedCountry.textContent = initialValue;
|
||||
const country = countries.find(c => c.call_code === initialValue);
|
||||
if (country) {
|
||||
selectedFlag.className = `fi fi-${country.flag.toLowerCase()} me-2`;
|
||||
}
|
||||
}
|
||||
|
||||
// Search functionality
|
||||
searchInput.addEventListener('input', function() {
|
||||
const searchTerm = this.value.toLowerCase();
|
||||
const items = listElement.querySelectorAll('.dropdown-item');
|
||||
items.forEach(item => {
|
||||
const searchData = item.getAttribute('data-search');
|
||||
if (searchData.includes(searchTerm)) {
|
||||
item.style.display = '';
|
||||
} else {
|
||||
item.style.display = 'none';
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(error => console.error('Error loading countries:', error));
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@endsection
|
||||
|
||||
@ -44,9 +44,23 @@
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="mobile" class="form-label">Mobile Number</label>
|
||||
<input type="text" class="form-control @error('mobile') is-invalid @enderror" id="mobile" name="mobile" value="{{ old('mobile', $user->mobile) }}">
|
||||
<div class="input-group" onclick="event.stopPropagation()">
|
||||
<button class="btn btn-outline-secondary dropdown-toggle country-dropdown-btn d-flex align-items-center" type="button" id="country_codeDropdown" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<span class="fi fi-bh me-2" id="country_codeSelectedFlag"></span>
|
||||
<span class="country-label" id="country_codeSelectedCountry">{{ old('mobile_code', $user->mobile_code ?? '+973') }}</span>
|
||||
</button>
|
||||
<div class="dropdown-menu p-2" aria-labelledby="country_codeDropdown" style="min-width: 200px;" onclick="event.stopPropagation()">
|
||||
<input type="text" class="form-control form-control-sm mb-2" placeholder="Search country..." id="country_codeSearch" onkeydown="event.stopPropagation()">
|
||||
<div class="country-list" id="country_codeList" style="max-height: 300px; overflow-y: auto;"></div>
|
||||
</div>
|
||||
<input type="hidden" id="country_code" name="mobile_code" value="{{ old('mobile_code', $user->mobile['code'] ?? '+973') }}" required="">
|
||||
<input id="mobile_number" type="tel" class="form-control @error('mobile') is-invalid @enderror" name="mobile" value="{{ old('mobile', $user->mobile['number'] ?? '') }}" required="" autocomplete="tel" placeholder="Phone number">
|
||||
</div>
|
||||
@error('mobile')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
<div class="invalid-feedback d-block">{{ $message }}</div>
|
||||
@enderror
|
||||
@error('mobile_code')
|
||||
<div class="invalid-feedback d-block">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
@ -174,7 +188,7 @@
|
||||
|
||||
<div class="d-flex justify-content-between">
|
||||
<a href="{{ route('profile.show') }}" class="btn btn-outline-secondary">Cancel</a>
|
||||
<button type="submit" class="btn btn-primary">Update Profile</button>
|
||||
<button type="submit" class="btn btn-primary">Update</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@ -192,8 +206,72 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Load countries for mobile code dropdown
|
||||
fetch('/data/countries.json')
|
||||
.then(response => response.json())
|
||||
.then(countries => {
|
||||
const listElement = document.getElementById('country_codeList');
|
||||
const selectedFlag = document.getElementById('country_codeSelectedFlag');
|
||||
const selectedCountry = document.getElementById('country_codeSelectedCountry');
|
||||
const hiddenInput = document.getElementById('country_code');
|
||||
const searchInput = document.getElementById('country_codeSearch');
|
||||
|
||||
if (!listElement) return;
|
||||
|
||||
// Populate dropdown
|
||||
countries.forEach(country => {
|
||||
const button = document.createElement('button');
|
||||
button.className = 'dropdown-item d-flex align-items-center';
|
||||
button.type = 'button';
|
||||
button.setAttribute('data-country-code', country.call_code);
|
||||
button.setAttribute('data-country-name', country.name);
|
||||
button.setAttribute('data-flag-code', country.flag);
|
||||
button.setAttribute('data-search', `${country.name.toLowerCase()} ${country.call_code}`);
|
||||
button.innerHTML = `<span class="fi fi-${country.flag.toLowerCase()} me-2"></span><span>${country.name} (${country.call_code})</span>`;
|
||||
button.addEventListener('click', function() {
|
||||
const code = this.getAttribute('data-country-code');
|
||||
const flag = this.getAttribute('data-flag-code');
|
||||
const name = this.getAttribute('data-country-name');
|
||||
selectedFlag.className = `fi fi-${flag.toLowerCase()} me-2`;
|
||||
selectedCountry.textContent = code;
|
||||
hiddenInput.value = code;
|
||||
// Close dropdown
|
||||
const dropdown = bootstrap.Dropdown.getInstance(document.getElementById('country_codeDropdown'));
|
||||
if (dropdown) dropdown.hide();
|
||||
});
|
||||
listElement.appendChild(button);
|
||||
});
|
||||
|
||||
// Set initial value
|
||||
const initialValue = '{{ old('mobile_code', $user->mobile['code'] ?? '+973') }}';
|
||||
if (initialValue) {
|
||||
hiddenInput.value = initialValue;
|
||||
selectedCountry.textContent = initialValue;
|
||||
const country = countries.find(c => c.call_code === initialValue);
|
||||
if (country) {
|
||||
selectedFlag.className = `fi fi-${country.flag.toLowerCase()} me-2`;
|
||||
}
|
||||
}
|
||||
|
||||
// Search functionality
|
||||
searchInput.addEventListener('input', function() {
|
||||
const searchTerm = this.value.toLowerCase();
|
||||
const items = listElement.querySelectorAll('.dropdown-item');
|
||||
items.forEach(item => {
|
||||
const searchData = item.getAttribute('data-search');
|
||||
if (searchData.includes(searchTerm)) {
|
||||
item.style.display = '';
|
||||
} else {
|
||||
item.style.display = 'none';
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(error => console.error('Error loading countries:', error));
|
||||
|
||||
let socialLinkIndex = {{ count($formLinks ?? []) }};
|
||||
|
||||
// Add new social link row
|
||||
@ -258,4 +336,5 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@endsection
|
||||
|
||||
@ -9,18 +9,22 @@
|
||||
<p class="text-muted mb-0">Comprehensive member information and analytics</p>
|
||||
</div>
|
||||
<div>
|
||||
@if($relationship->relationship_type == 'self')
|
||||
<a href="{{ route('profile.edit') }}" class="btn btn-primary me-2">
|
||||
<i class="bi bi-pencil me-1"></i>Edit Profile
|
||||
</a>
|
||||
@else
|
||||
<a href="{{ route('family.edit', $relationship->dependent->id) }}" class="btn btn-primary me-2">
|
||||
<i class="bi bi-pencil me-1"></i>Edit Member
|
||||
</a>
|
||||
@endif
|
||||
<a href="{{ route('family.dashboard') }}" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-arrow-left me-2"></i>Back to Family
|
||||
</a>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-primary rounded-pill dropdown-toggle" type="button" id="actionDropdown" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-lightning me-1"></i>Action
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="actionDropdown">
|
||||
<li><a class="dropdown-item" href="@if($relationship->relationship_type == 'self'){{ route('profile.edit') }}@else{{ route('family.edit', $relationship->dependent->id) }}@endif">
|
||||
<i class="bi bi-pencil me-2"></i>Edit Info
|
||||
</a></li>
|
||||
<li><a class="dropdown-item" href="#"><i class="bi bi-calendar-check me-2"></i>Add Attendance Record</a></li>
|
||||
<li><a class="dropdown-item" href="#"><i class="bi bi-heart-pulse me-2"></i>Add Health Update</a></li>
|
||||
<li><a class="dropdown-item" href="#"><i class="bi bi-bullseye me-2"></i>Set a Goal</a></li>
|
||||
<li><a class="dropdown-item" href="#"><i class="bi bi-trophy me-2"></i>Add Achievement</a></li>
|
||||
<li><a class="dropdown-item" href="#"><i class="bi bi-award me-2"></i>Add Tournament Participation</a></li>
|
||||
<li><a class="dropdown-item" href="#"><i class="bi bi-calendar-event me-2"></i>Add Event Participation</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -474,80 +478,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Club Memberships -->
|
||||
<div class="card shadow-sm border-0 mb-4">
|
||||
<div class="card-body p-4">
|
||||
<h5 class="fw-bold mb-3">Club Memberships</h5>
|
||||
@if($relationship->dependent->memberClubs->count() > 0)
|
||||
<div class="row g-3">
|
||||
@foreach($relationship->dependent->memberClubs as $club)
|
||||
<div class="col-md-6">
|
||||
<div class="border rounded p-3">
|
||||
<div class="d-flex justify-content-between align-items-start">
|
||||
<div>
|
||||
<h6 class="fw-bold mb-1">{{ $club->club_name }}</h6>
|
||||
<small class="text-muted">Status: {{ ucfirst($club->pivot->status) }}</small>
|
||||
</div>
|
||||
<span class="badge bg-{{ $club->pivot->status === 'active' ? 'success' : 'secondary' }}">
|
||||
{{ ucfirst($club->pivot->status) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
<p class="text-center text-muted my-4">No club memberships found.</p>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recent Invoices -->
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body p-4">
|
||||
<h5 class="fw-bold mb-3">Recent Invoices</h5>
|
||||
@if($relationship->dependent->studentInvoices->count() > 0)
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Club</th>
|
||||
<th>Amount</th>
|
||||
<th>Status</th>
|
||||
<th>Due Date</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($relationship->dependent->studentInvoices->take(5) as $invoice)
|
||||
<tr>
|
||||
<td>{{ $invoice->tenant->club_name }}</td>
|
||||
<td>${{ number_format($invoice->amount, 2) }}</td>
|
||||
<td>
|
||||
@if($invoice->status === 'paid')
|
||||
<span class="badge bg-success">Paid</span>
|
||||
@elseif($invoice->status === 'pending')
|
||||
<span class="badge bg-warning text-dark">Pending</span>
|
||||
@else
|
||||
<span class="badge bg-danger">Overdue</span>
|
||||
@endif
|
||||
</td>
|
||||
<td>{{ $invoice->due_date->format('M j, Y') }}</td>
|
||||
<td>
|
||||
<a href="{{ route('invoices.show', $invoice->id) }}" class="btn btn-sm btn-outline-primary">
|
||||
View
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@else
|
||||
<p class="text-center text-muted my-4">No invoices found.</p>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Attendance Tab -->
|
||||
|
||||
@ -244,6 +244,15 @@
|
||||
.notification-item.unread {
|
||||
background-color: hsl(var(--accent));
|
||||
}
|
||||
|
||||
.dropdown-item:hover {
|
||||
background-color: hsl(var(--primary)) !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.nav-icon-btn.dropdown-toggle::after {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@stack('styles')
|
||||
@ -274,6 +283,18 @@
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<!-- Messages Dropdown -->
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link nav-icon-btn dropdown-toggle" href="#" id="messagesDropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" title="Messages">
|
||||
<i class="bi bi-chat" style="font-size: 1.25rem;"></i>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-end" aria-labelledby="messagesDropdown">
|
||||
<h6 class="dropdown-header small">Messages</h6>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item small" href="#">No new messages</a>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<!-- Notifications Dropdown -->
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link nav-icon-btn dropdown-toggle" href="#" id="notificationDropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" title="Notifications">
|
||||
@ -337,21 +358,44 @@
|
||||
{{ strtoupper(substr(Auth::user()->full_name, 0, 1)) }}
|
||||
</span>
|
||||
@endif
|
||||
{{ Auth::user()->full_name }}
|
||||
</a>
|
||||
|
||||
<div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
|
||||
<a class="dropdown-item" href="{{ route('family.dashboard') }}">
|
||||
<i class="bi bi-people me-2"></i>Family
|
||||
<h6 class="dropdown-header small"><strong>{{ Auth::user()->full_name }}</strong><br><small>{{ Auth::user()->email }}</small></h6>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item small" href="{{ url('profile') }}">
|
||||
<i class="bi bi-person me-2"></i>My Profile
|
||||
</a>
|
||||
<a class="dropdown-item" href="{{ route('invoices.index') }}">
|
||||
<i class="bi bi-receipt me-2"></i>Invoices
|
||||
<a class="dropdown-item small" href="#">
|
||||
<i class="bi bi-diagram-3 me-2"></i>Affiliations
|
||||
</a>
|
||||
<a class="dropdown-item small" href="#">
|
||||
<i class="bi bi-calendar-event me-2"></i>My Sessions
|
||||
</a>
|
||||
<a class="dropdown-item small" href="{{ route('family.dashboard') }}">
|
||||
<i class="bi bi-people me-2"></i>My Family
|
||||
</a>
|
||||
<a class="dropdown-item small" href="#">
|
||||
<i class="bi bi-gear me-2"></i>Settings
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="{{ route('logout') }}"
|
||||
@if(Auth::user()->has_business ?? false)
|
||||
<a class="dropdown-item small" href="#">
|
||||
<i class="bi bi-building me-2"></i>Manage My Business
|
||||
</a>
|
||||
@endif
|
||||
@if((Auth::user()->is_super_admin ?? false) || (Auth::user()->is_moderator ?? false))
|
||||
<a class="dropdown-item small" href="#">
|
||||
<i class="bi bi-shield me-2"></i>Admin Panel
|
||||
</a>
|
||||
@endif
|
||||
@if((Auth::user()->has_business ?? false) || ((Auth::user()->is_super_admin ?? false) || (Auth::user()->is_moderator ?? false)))
|
||||
<div class="dropdown-divider"></div>
|
||||
@endif
|
||||
<a class="dropdown-item small" href="{{ route('logout') }}"
|
||||
onclick="event.preventDefault();
|
||||
document.getElementById('logout-form').submit();">
|
||||
<i class="bi bi-box-arrow-right me-2"></i>{{ __('Logout') }}
|
||||
<i class="bi bi-box-arrow-right me-2"></i>Sign Out
|
||||
</a>
|
||||
|
||||
<form id="logout-form" action="{{ route('logout') }}" method="POST" class="d-none">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user