built user profile added the logo created the family view etc

This commit is contained in:
ghassan committed 2026-01-20 16:19:00 +03:00
1 parent 4a7353e3fc
commit 43c2676d6f
33 files changed
+3783 -257

No files matched your search

@@ -0,0 +1,52 @@
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center align-items-center" style="min-height: 80vh;">
<div class="col-md-6 col-lg-4">
<div class="card shadow">
<div class="card-body p-4">
<div class="text-center mb-4">
<h3 class="fw-bold">Forgot Password?</h3>
<p class="text-muted">No problem. Just let us know your email address and we'll email you a password reset link.</p>
</div>
<form method="POST" action="{{ route('password.email') }}">
@csrf
<!-- Email Address -->
<div class="mb-3">
<label for="email" class="form-label">Email Address</label>
<input id="email" type="email"
class="form-control @error('email') is-invalid @enderror"
name="email"
value="{{ old('email') }}"
required autocomplete="email"
autofocus>
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
<!-- Send Password Reset Link Button -->
<div class="d-grid mb-3">
<button type="submit" class="btn btn-primary">
Send Password Reset Link
</button>
</div>
<!-- Back to Login -->
<div class="text-center">
<a href="{{ route('login') }}" class="text-decoration-none">
Back to Login
</a>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
+76
View File
@@ -0,0 +1,76 @@
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center align-items-center" style="min-height: 80vh;">
<div class="col-md-6 col-lg-4">
<div class="card shadow">
<div class="card-body p-4">
<div class="text-center mb-4">
<h3 class="fw-bold">Welcome Back</h3>
<p class="text-muted">Sign in to your account</p>
</div>
<form method="POST" action="{{ route('login') }}">
@csrf
<!-- Email Address -->
<div class="mb-3">
<label for="email" class="form-label">Email Address</label>
<input id="email" type="email"
class="form-control @error('email') is-invalid @enderror"
name="email"
value="{{ old('email') }}"
required autocomplete="email"
autofocus>
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
<!-- Password -->
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input id="password" type="password"
class="form-control @error('password') is-invalid @enderror"
name="password"
required autocomplete="current-password">
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
<!-- Remember Me -->
<div class="mb-3 form-check">
<input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>
<label class="form-check-label" for="remember">
Remember Me
</label>
</div>
<!-- Login Button -->
<div class="d-grid mb-3">
<button type="submit" class="btn btn-primary">
Login
</button>
</div>
<!-- Forgot Password Link -->
<div class="text-center">
@if (Route::has('password.request'))
<a class="text-decoration-none" href="{{ route('password.request') }}">
Forgot Password?
</a>
@endif
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
+236
View File
@@ -0,0 +1,236 @@
@extends('layouts.app')
@section('content')
<style>
.register-container {
min-height: calc(100vh - 72px);
display: flex;
align-items: center;
justify-content: center;
padding: 2rem 0;
}
.flatpickr-input {
width: 100%;
padding: 0.375rem 0.75rem;
font-size: 1rem;
line-height: 1.5;
color: #212529;
background-color: #fff;
border: 1px solid #ced4da;
border-radius: 0.375rem;
}
.flatpickr-input:focus {
border-color: #86b7fe;
outline: 0;
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
}
</style>
<!-- Flag Icons CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/css/flag-icons.min.css">
<!-- Select2 CSS (for nationality dropdown) -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/select2.min.css" rel="stylesheet" />
<!-- Flatpickr CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
<div class="container register-container">
<div class="row justify-content-center">
<div class="col-lg-10">
<div class="card shadow">
<div class="card-header bg-white py-3">
<h3 class="text-center mb-0 fw-bold">Create Your Profile</h3>
</div>
<div class="card-body p-4">
<form method="POST" action="{{ route('register') }}" id="registrationForm">
@csrf
<div class="row">
<!-- Left Column -->
<div class="col-md-6">
<!-- Full Name -->
<div class="mb-3">
<label for="full_name" class="form-label">Full Name</label>
<input id="full_name" type="text"
class="form-control @error('full_name') is-invalid @enderror"
name="full_name"
value="{{ old('full_name') }}"
required autocomplete="name">
@error('full_name')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
<!-- Email Address -->
<div class="mb-3">
<label for="email" class="form-label">Email Address</label>
<input id="email" type="email"
class="form-control @error('email') is-invalid @enderror"
name="email"
value="{{ old('email') }}"
required autocomplete="email">
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
<!-- Password -->
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input id="password" type="password"
class="form-control @error('password') is-invalid @enderror"
name="password"
required autocomplete="new-password">
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
<!-- Confirm Password -->
<div class="mb-3">
<label for="password-confirm" class="form-label">Confirm Password</label>
<input id="password-confirm" type="password"
class="form-control"
name="password_confirmation"
required autocomplete="new-password">
</div>
</div>
<!-- Right Column -->
<div class="col-md-6">
<!-- Mobile Number with Country Code -->
<div class="mb-3">
<label for="mobile_number" class="form-label">Mobile Number</label>
<x-country-code-dropdown
name="country_code"
id="country_code"
:value="old('country_code', '+1')"
:required="true"
:error="$errors->first('country_code')">
<input id="mobile_number" type="tel"
class="form-control @error('mobile_number') is-invalid @enderror"
name="mobile_number"
value="{{ old('mobile_number') }}"
required autocomplete="tel"
placeholder="Phone number">
</x-country-code-dropdown>
@error('mobile_number')
<span class="invalid-feedback d-block" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
<!-- Gender -->
<div class="mb-3">
<label for="gender" class="form-label">Gender</label>
<select id="gender" class="form-select @error('gender') is-invalid @enderror"
name="gender" required>
<option value="">Select Gender</option>
<option value="m" {{ old('gender') == 'm' ? 'selected' : '' }}>Male</option>
<option value="f" {{ old('gender') == 'f' ? 'selected' : '' }}>Female</option>
</select>
@error('gender')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
<!-- Birthdate -->
<div class="mb-3">
<label for="birthdate" class="form-label">Birthdate</label>
<input id="birthdate" type="text"
class="flatpickr-input @error('birthdate') is-invalid @enderror"
name="birthdate"
value="{{ old('birthdate') }}"
required
placeholder="Select birthdate"
readonly>
@error('birthdate')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
<!-- Nationality -->
<div class="mb-3">
<x-country-dropdown
name="nationality"
id="nationality"
:value="old('nationality')"
:required="true"
:error="$errors->first('nationality')" />
</div>
</div>
</div>
<!-- Register Button -->
<div class="d-grid mt-4">
<button type="submit" class="btn btn-primary btn-lg" id="registerButton">
Create Account
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<!-- jQuery (required for Select2) -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- Select2 JS -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/select2.min.js"></script>
<!-- Flatpickr JS -->
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
@stack('styles')
@stack('scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
// Initialize Flatpickr for birthdate
flatpickr('#birthdate', {
dateFormat: 'Y-m-d',
maxDate: 'today',
yearRange: [1900, new Date().getFullYear()],
disableMobile: true,
showMonths: 1,
clickOpens: true,
onReady: function(selectedDates, dateStr, instance) {
const calendar = instance.calendarContainer;
calendar.style.fontSize = '14px';
}
});
// Form submission handler
$('#registrationForm').on('submit', function(e) {
console.log('Form submitting...');
console.log('Country code:', $('#country_code').val());
console.log('Nationality:', $('#nationality').val());
console.log('Mobile number:', $('#mobile_number').val());
});
// Error handler
window.onerror = function(message, source, lineno, colno, error) {
console.error('JavaScript Error:', message);
console.error('Source:', source);
console.error('Line:', lineno);
console.error('Error:', error);
};
});
</script>
@endsection
@@ -0,0 +1,78 @@
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center align-items-center" style="min-height: 80vh;">
<div class="col-md-6 col-lg-4">
<div class="card shadow">
<div class="card-body p-4">
<div class="text-center mb-4">
<h3 class="fw-bold">Reset Password</h3>
<p class="text-muted">Enter your new password below.</p>
</div>
<form method="POST" action="{{ route('password.update') }}">
@csrf
<!-- Token -->
<input type="hidden" name="token" value="{{ $request->token }}">
<!-- Email Address -->
<div class="mb-3">
<label for="email" class="form-label">Email Address</label>
<input id="email" type="email"
class="form-control @error('email') is-invalid @enderror"
name="email"
value="{{ $email ?? old('email') }}"
required autocomplete="email"
autofocus>
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
<!-- Password -->
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input id="password" type="password"
class="form-control @error('password') is-invalid @enderror"
name="password"
required autocomplete="new-password">
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
<!-- Confirm Password -->
<div class="mb-3">
<label for="password-confirm" class="form-label">Confirm Password</label>
<input id="password-confirm" type="password"
class="form-control"
name="password_confirmation"
required autocomplete="new-password">
</div>
<!-- Reset Password Button -->
<div class="d-grid mb-3">
<button type="submit" class="btn btn-primary">
Reset Password
</button>
</div>
<!-- Back to Login -->
<div class="text-center">
<a href="{{ route('login') }}" class="text-decoration-none">
Back to Login
</a>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
+331
View File
@@ -0,0 +1,331 @@
# Reusable Form Components
This directory contains reusable Blade components for forms across the application.
## Available Components
### 1. Country Dropdown (`<x-country-dropdown />`)
A dropdown with country flags that stores the ISO3 country code.
**Features:**
- Flag icons for each country
- Loads data from `/data/countries.json`
- Preserves selected value on validation errors
- Displays validation errors
- Clean, modern UI with flag icons
**Usage:**
```blade
<x-country-dropdown
name="country"
id="country"
:value="old('country')"
:required="true"
:error="$errors->first('country')" />
```
**Props:**
- `name` (default: 'country') - The name attribute for the select
- `id` (default: 'country') - The ID for the select element
- `value` (default: '') - The initial/selected value (ISO3 code)
- `required` (default: false) - Whether the field is required
- `error` (default: null) - Error message to display
**Example in a form:**
```blade
<div class="mb-3">
<label for="country" class="form-label">Country</label>
<x-country-dropdown
name="country"
id="country"
:value="old('country', 'USA')"
:required="true"
:error="$errors->first('country')" />
</div>
```
---
### 2. Call Code Dropdown (`<x-call-code-dropdown />`)
A dropdown with country flags and call codes that stores the call code.
**Features:**
- Flag icons for each country
- Displays country name and call code
- Loads data from `/data/countries.json`
- Preserves selected value on validation errors
- Displays validation errors
**Usage:**
```blade
<x-call-code-dropdown
name="country_code"
id="country_code"
:value="old('country_code', '+971')"
:required="true"
:error="$errors->first('country_code')" />
```
**Props:**
- `name` (default: 'call_code') - The name attribute for the select
- `id` (default: 'call_code') - The ID for the select element
- `value` (default: '') - The initial/selected value (call code)
- `required` (default: false) - Whether the field is required
- `error` (default: null) - Error message to display
**Example in a form:**
```blade
<div class="mb-3">
<label for="country_code" class="form-label">Country Code</label>
<x-call-code-dropdown
name="country_code"
id="country_code"
:value="old('country_code', '+971')"
:required="true"
:error="$errors->first('country_code')" />
</div>
```
---
### 3. Currency Dropdown (`<x-currency-dropdown />`)
A dropdown with country flags and currency symbols that stores the currency code.
**Features:**
- Flag icons for each country
- Displays country name, currency code, and currency symbol
- Loads data from `/data/countries.json`
- Preserves selected value on validation errors
- Displays validation errors
**Usage:**
```blade
<x-currency-dropdown
name="currency"
id="currency"
:value="old('currency', 'USD')"
:required="true"
:error="$errors->first('currency')" />
```
**Props:**
- `name` (default: 'currency') - The name attribute for the select
- `id` (default: 'currency') - The ID for the select element
- `value` (default: '') - The initial/selected value (currency code)
- `required` (default: false) - Whether the field is required
- `error` (default: null) - Error message to display
**Example in a form:**
```blade
<div class="mb-3">
<label for="currency" class="form-label">Currency</label>
<x-currency-dropdown
name="currency"
id="currency"
:value="old('currency', 'USD')"
:required="true"
:error="$errors->first('currency')" />
</div>
```
---
### 4. Timezone Dropdown (`<x-timezone-dropdown />`)
A dropdown with country flags and timezones that stores the timezone.
**Features:**
- Flag icons for each country
- Displays country name and timezone
- Loads data from `/data/countries.json`
- Preserves selected value on validation errors
- Displays validation errors
**Usage:**
```blade
<x-timezone-dropdown
name="timezone"
id="timezone"
:value="old('timezone', 'Asia/Dubai')"
:required="true"
:error="$errors->first('timezone')" />
```
**Props:**
- `name` (default: 'timezone') - The name attribute for the select
- `id` (default: 'timezone') - The ID for the select element
- `value` (default: '') - The initial/selected value (timezone)
- `required` (default: false) - Whether the field is required
- `error` (default: null) - Error message to display
**Example in a form:**
```blade
<div class="mb-3">
<label for="timezone" class="form-label">Timezone</label>
<x-timezone-dropdown
name="timezone"
id="timezone"
:value="old('timezone', 'Asia/Dubai')"
:required="true"
:error="$errors->first('timezone')" />
</div>
```
---
## Dependencies
All components require:
### Flag Icons
```html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flag-icons@6.6.6/css/flag-icons.min.css">
```
### Countries Data File
All components load country data from `/public/data/countries.json` which contains:
- Country name
- ISO2 code (2-letter)
- ISO3 code (3-letter)
- Flag code (for flag-icons)
- Call code (phone country code)
- Currency code
- Currency symbol
- Timezone
**Note:** Israel is excluded from the countries list as requested.
---
## Complete Example Form
Here's a complete example of a form using all components:
```blade
@extends('layouts.app')
@section('content')
<!-- Flag Icons CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flag-icons@6.6.6/css/flag-icons.min.css">
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">
<h4>User Information</h4>
</div>
<div class="card-body">
<form method="POST" action="#">
@csrf
<!-- Country Dropdown -->
<x-country-dropdown
name="country"
id="country"
:value="old('country', 'USA')"
:required="true"
:error="$errors->first('country')" />
<!-- Call Code Dropdown -->
<x-call-code-dropdown
name="country_code"
id="country_code"
:value="old('country_code', '+971')"
:required="true"
:error="$errors->first('country_code')" />
<!-- Currency Dropdown -->
<x-currency-dropdown
name="currency"
id="currency"
:value="old('currency', 'USD')"
:required="true"
:error="$errors->first('currency')" />
<!-- Timezone Dropdown -->
<x-timezone-dropdown
name="timezone"
id="timezone"
:value="old('timezone', 'Asia/Dubai')"
:required="true"
:error="$errors->first('timezone')" />
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
</div>
</div>
</div>
<!-- Load component scripts -->
@stack('scripts')
@endsection
```
---
## Notes
1. **Data Loading**: All components use JavaScript's `fetch()` API to load country data from `/data/countries.json`. This ensures the data is loaded asynchronously and doesn't block page rendering.
2. **Value Preservation**: All components support Laravel's `old()` helper to preserve selected values after validation errors.
3. **Validation**: All components integrate with Laravel's validation system and display error messages when validation fails.
4. **Flag Icons**: All components use the flag-icons library (v6.6.6) for displaying country flags.
5. **Multiple Instances**: You can use multiple instances of any component on the same page. Each instance will work independently.
6. **Custom Styling**: Each component includes custom CSS for flag positioning and sizing.
7. **Unique Values**:
- Currency dropdown shows unique currencies (countries with same currency are grouped)
- Timezone dropdown shows unique timezones (countries with same timezone are grouped)
8. **Israel Excluded**: As requested, Israel is not included in the countries.json file.
---
## Component Comparison
| Component | Displays | Stores | Example Value |
|-----------|----------|--------|---------------|
| Country Dropdown | Flag + Country Name | ISO3 Code | USA, GBR, ARE |
| Call Code Dropdown | Flag + Name + Call Code | Call Code | +1, +44, +971 |
| Currency Dropdown | Flag + Name + Currency | Currency Code | USD, EUR, AED |
| Timezone Dropdown | Flag + Name + Timezone | Timezone | America/New_York, Europe/London, Asia/Dubai |
---
## Troubleshooting
**Flags not displaying:**
- Ensure flag-icons CSS is loaded in your layout or view
- Check browser console for any CSS loading errors
**Dropdown not populating:**
- Check that `/public/data/countries.json` exists and is accessible
- Check browser console for any fetch errors
- Ensure the file path is correct
**Values not preserving after validation:**
- Ensure you're passing the correct value to the `:value` prop
- Use `old('field_name')` to get the previous value
- Check that the field name matches your validation rules
**Multiple instances conflicting:**
- Each component uses a unique ID based on the `id` prop
- Ensure each instance has a unique `id` prop value
@@ -0,0 +1,79 @@
@props(['name' => 'call_code', 'id' => 'call_code', 'value' => '', 'required' => false, 'error' => null])
<div class="mb-3">
<label for="{{ $id }}" class="form-label">Country Code</label>
<select id="{{ $id }}"
class="form-select call-code-select @error($name) is-invalid @enderror"
name="{{ $name }}"
{{ $required ? 'required' : '' }}>
<option value="">Select Country Code</option>
</select>
@if($error)
<span class="invalid-feedback" role="alert">
<strong>{{ $error }}</strong>
</span>
@endif
</div>
@once
@push('scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
// Load countries from JSON file
fetch('/data/countries.json')
.then(response => response.json())
.then(countries => {
const selectElement = document.getElementById('{{ $id }}');
if (!selectElement) return;
// Populate dropdown
countries.forEach(country => {
const option = document.createElement('option');
option.value = country.call_code;
option.textContent = `${country.name} (${country.call_code})`;
option.setAttribute('data-flag', country.flag);
selectElement.appendChild(option);
});
// Set initial value if provided
const initialValue = '{{ $value }}';
if (initialValue) {
selectElement.value = initialValue;
}
// Initialize Select2 for searchable dropdown
if (typeof $ !== 'undefined' && $.fn.select2) {
$(selectElement).select2({
templateResult: function(state) {
if (!state.id) {
return state.text;
}
const option = $(state.element);
const flagCode = option.data('flag');
return $(`<span><span class="fi fi-${flagCode} me-2"></span>${state.text}</span>`);
},
templateSelection: function(state) {
if (!state.id) {
return state.text;
}
const option = $(state.element);
const flagCode = option.data('flag');
return $(`<span><span class="fi fi-${flagCode} me-2"></span>${state.text}</span>`);
},
width: '100%'
});
}
})
.catch(error => console.error('Error loading countries:', error));
});
</script>
@endpush
@push('styles')
<style>
.call-code-select {
background-size: 20px 15px;
}
</style>
@endpush
@endonce
@@ -0,0 +1,191 @@
@props(['name' => 'country_code', 'id' => 'country_code', 'value' => '+1', 'required' => false, 'error' => null])
<div class="input-group">
<button class="btn btn-outline-secondary dropdown-toggle country-dropdown-btn d-flex align-items-center"
type="button"
id="{{ $id }}Dropdown"
data-bs-toggle="dropdown"
aria-expanded="false">
<span class="fi fi-us me-2" id="{{ $id }}SelectedFlag"></span>
<span class="country-label" id="{{ $id }}SelectedCountry">{{ $value }}</span>
</button>
<div class="dropdown-menu p-2" aria-labelledby="{{ $id }}Dropdown" style="min-width: 300px;">
<input type="text"
class="form-control form-control-sm mb-2"
placeholder="Search country..."
id="{{ $id }}Search">
<div class="country-list" id="{{ $id }}List" style="max-height: 300px; overflow-y: auto;">
<!-- Countries will be populated by JavaScript -->
</div>
</div>
<input type="hidden" id="{{ $id }}" name="{{ $name }}" value="{{ $value }}" {{ $required ? 'required' : '' }}>
{{ $slot }}
</div>
@if($error)
<span class="invalid-feedback d-block" role="alert">
<strong>{{ $error }}</strong>
</span>
@endif
@once
@push('styles')
<style>
.country-dropdown-btn {
min-width: 150px;
display: flex;
align-items: center;
justify-content: space-between;
}
.country-list {
max-height: 300px;
overflow-y: auto;
}
.dropdown-item {
cursor: pointer;
}
.dropdown-item:hover {
background-color: #f8f9fa;
}
</style>
@endpush
@push('scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
// Country data with flags and codes
const countries = [
{ code: '+1', name: 'United States', flagCode: 'us' },
{ code: '+1', name: 'Canada', flagCode: 'ca' },
{ code: '+44', name: 'United Kingdom', flagCode: 'gb' },
{ code: '+971', name: 'United Arab Emirates', flagCode: 'ae' },
{ code: '+966', name: 'Saudi Arabia', flagCode: 'sa' },
{ code: '+974', name: 'Qatar', flagCode: 'qa' },
{ code: '+965', name: 'Kuwait', flagCode: 'kw' },
{ code: '+973', name: 'Bahrain', flagCode: 'bh' },
{ code: '+968', name: 'Oman', flagCode: 'om' },
{ code: '+20', name: 'Egypt', flagCode: 'eg' },
{ code: '+91', name: 'India', flagCode: 'in' },
{ code: '+92', name: 'Pakistan', flagCode: 'pk' },
{ code: '+880', name: 'Bangladesh', flagCode: 'bd' },
{ code: '+60', name: 'Malaysia', flagCode: 'my' },
{ code: '+65', name: 'Singapore', flagCode: 'sg' },
{ code: '+81', name: 'Japan', flagCode: 'jp' },
{ code: '+86', name: 'China', flagCode: 'cn' },
{ code: '+82', name: 'South Korea', flagCode: 'kr' },
{ code: '+61', name: 'Australia', flagCode: 'au' },
{ code: '+49', name: 'Germany', flagCode: 'de' },
{ code: '+33', name: 'France', flagCode: 'fr' },
{ code: '+39', name: 'Italy', flagCode: 'it' },
{ code: '+34', name: 'Spain', flagCode: 'es' },
{ code: '+31', name: 'Netherlands', flagCode: 'nl' },
{ code: '+46', name: 'Sweden', flagCode: 'se' },
{ code: '+47', name: 'Norway', flagCode: 'no' },
{ code: '+45', name: 'Denmark', flagCode: 'dk' },
{ code: '+358', name: 'Finland', flagCode: 'fi' },
{ code: '+41', name: 'Switzerland', flagCode: 'ch' },
{ code: '+43', name: 'Austria', flagCode: 'at' },
{ code: '+48', name: 'Poland', flagCode: 'pl' },
{ code: '+420', name: 'Czech Republic', flagCode: 'cz' },
{ code: '+36', name: 'Hungary', flagCode: 'hu' },
{ code: '+40', name: 'Romania', flagCode: 'ro' },
{ code: '+30', name: 'Greece', flagCode: 'gr' },
{ code: '+90', name: 'Turkey', flagCode: 'tr' },
{ code: '+7', name: 'Russia', flagCode: 'ru' },
{ code: '+55', name: 'Brazil', flagCode: 'br' },
{ code: '+52', name: 'Mexico', flagCode: 'mx' },
{ code: '+54', name: 'Argentina', flagCode: 'ar' },
{ code: '+56', name: 'Chile', flagCode: 'cl' },
{ code: '+57', name: 'Colombia', flagCode: 'co' },
{ code: '+27', name: 'South Africa', flagCode: 'za' },
{ code: '+234', name: 'Nigeria', flagCode: 'ng' },
{ code: '+254', name: 'Kenya', flagCode: 'ke' },
{ code: '+94', name: 'Sri Lanka', flagCode: 'lk' },
{ code: '+84', name: 'Vietnam', flagCode: 'vn' },
{ code: '+66', name: 'Thailand', flagCode: 'th' },
{ code: '+62', name: 'Indonesia', flagCode: 'id' },
{ code: '+63', name: 'Philippines', flagCode: 'ph' },
{ code: '+64', name: 'New Zealand', flagCode: 'nz' },
{ code: '+351', name: 'Portugal', flagCode: 'pt' },
{ code: '+353', name: 'Ireland', flagCode: 'ie' },
{ code: '+972', name: 'Israel', flagCode: 'il' },
{ code: '+962', name: 'Jordan', flagCode: 'jo' },
{ code: '+961', name: 'Lebanon', flagCode: 'lb' },
{ code: '+964', name: 'Iraq', flagCode: 'iq' },
];
// Initialize all country code dropdowns on the page
document.querySelectorAll('[id$="List"]').forEach(function(listElement) {
const componentId = listElement.id.replace('List', '');
initializeCountryDropdown(componentId, countries);
});
function initializeCountryDropdown(componentId, countries) {
const countryList = document.getElementById(componentId + 'List');
if (!countryList) return;
// Populate country 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.code);
button.setAttribute('data-country-name', country.name);
button.setAttribute('data-flag-code', country.flagCode);
button.innerHTML = `
<span class="fi fi-${country.flagCode} me-2"></span>
<span>${country.name} (${country.code})</span>
`;
button.addEventListener('click', function() {
selectCountry(componentId, country.code, country.name, country.flagCode);
});
countryList.appendChild(button);
});
// Search functionality
const searchInput = document.getElementById(componentId + 'Search');
if (searchInput) {
searchInput.addEventListener('input', function(e) {
const searchTerm = e.target.value.toLowerCase();
const items = countryList.querySelectorAll('.dropdown-item');
items.forEach(item => {
const text = item.textContent.toLowerCase();
if (text.includes(searchTerm)) {
item.style.display = '';
} else {
item.style.display = 'none';
}
});
});
}
// Set initial value if provided
const hiddenInput = document.getElementById(componentId);
if (hiddenInput && hiddenInput.value) {
const initialCountry = countries.find(c => c.code === hiddenInput.value);
if (initialCountry) {
selectCountry(componentId, initialCountry.code, initialCountry.name, initialCountry.flagCode);
}
}
}
function selectCountry(componentId, code, name, flagCode) {
const flagElement = document.getElementById(componentId + 'SelectedFlag');
const countryElement = document.getElementById(componentId + 'SelectedCountry');
const hiddenInput = document.getElementById(componentId);
if (flagElement) flagElement.className = `fi fi-${flagCode} me-2`;
if (countryElement) countryElement.textContent = code;
if (hiddenInput) hiddenInput.value = code;
}
});
</script>
@endpush
@endonce
@@ -0,0 +1,80 @@
@props(['name' => 'country', 'id' => 'country', 'value' => '', 'required' => false, 'error' => null, 'label' => 'Nationality'])
<div class="mb-3">
<label for="{{ $id }}" class="form-label">{{ $label }}</label>
<select id="{{ $id }}"
class="form-select country-select @error($name) is-invalid @enderror"
name="{{ $name }}"
{{ $required ? 'required' : '' }}
style="width: 100%;">
<option value="">Select {{ $label }}</option>
</select>
@if($error)
<span class="invalid-feedback" role="alert">
<strong>{{ $error }}</strong>
</span>
@endif
</div>
@once
@push('scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
// Load countries from JSON file
fetch('/data/countries.json')
.then(response => response.json())
.then(countries => {
const selectElement = document.getElementById('{{ $id }}');
if (!selectElement) return;
// Populate dropdown
countries.forEach(country => {
const option = document.createElement('option');
option.value = country.iso3;
option.textContent = country.name;
option.setAttribute('data-flag', country.flag);
selectElement.appendChild(option);
});
// Set initial value if provided
const initialValue = '{{ $value }}';
if (initialValue) {
selectElement.value = initialValue;
}
// Initialize Select2 for searchable dropdown
if (typeof $ !== 'undefined' && $.fn.select2) {
$(selectElement).select2({
templateResult: function(state) {
if (!state.id) {
return state.text;
}
const option = $(state.element);
const flagCode = option.data('flag');
return $(`<span><span class="fi fi-${flagCode} me-2"></span>${state.text}</span>`);
},
templateSelection: function(state) {
if (!state.id) {
return state.text;
}
const option = $(state.element);
const flagCode = option.data('flag');
return $(`<span><span class="fi fi-${flagCode} me-2"></span>${state.text}</span>`);
},
width: '100%'
});
}
})
.catch(error => console.error('Error loading countries:', error));
});
</script>
@endpush
@push('styles')
<style>
.country-select {
background-size: 20px 15px;
}
</style>
@endpush
@endonce
@@ -0,0 +1,93 @@
@props(['name' => 'currency', 'id' => 'currency', 'value' => '', 'required' => false, 'error' => null])
<div class="mb-3">
<label for="{{ $id }}" class="form-label">Currency</label>
<select id="{{ $id }}"
class="form-select currency-select @error($name) is-invalid @enderror"
name="{{ $name }}"
{{ $required ? 'required' : '' }}>
<option value="">Select Currency</option>
</select>
@if($error)
<span class="invalid-feedback" role="alert">
<strong>{{ $error }}</strong>
</span>
@endif
</div>
@once
@push('scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
// Load countries from JSON file
fetch('/data/countries.json')
.then(response => response.json())
.then(countries => {
const selectElement = document.getElementById('{{ $id }}');
if (!selectElement) return;
// Get unique currencies
const uniqueCurrencies = {};
countries.forEach(country => {
if (!uniqueCurrencies[country.currency]) {
uniqueCurrencies[country.currency] = {
currency: country.currency,
currency_symbol: country.currency_symbol,
flag: country.flag,
name: country.name
};
}
}
});
// Populate dropdown
Object.values(uniqueCurrencies).forEach(currencyData => {
const option = document.createElement('option');
option.value = currencyData.currency;
option.textContent = `${currencyData.name} (${currencyData.currency} ${currencyData.currency_symbol})`;
option.setAttribute('data-flag', currencyData.flag);
selectElement.appendChild(option);
});
// Set initial value if provided
const initialValue = '{{ $value }}';
if (initialValue) {
selectElement.value = initialValue;
}
// Initialize Select2 for searchable dropdown
if (typeof $ !== 'undefined' && $.fn.select2) {
$(selectElement).select2({
templateResult: function(state) {
if (!state.id) {
return state.text;
}
const option = $(state.element);
const flagCode = option.data('flag');
return $(`<span><span class="fi fi-${flagCode} me-2"></span>${state.text}</span>`);
},
templateSelection: function(state) {
if (!state.id) {
return state.text;
}
const option = $(state.element);
const flagCode = option.data('flag');
return $(`<span><span class="fi fi-${flagCode} me-2"></span>${state.text}</span>`);
},
width: '100%'
});
}
})
.catch(error => console.error('Error loading countries:', error));
});
</script>
@endpush
@push('styles')
<style>
.currency-select {
background-size: 20px 15px;
}
</style>
@endpush
@endonce
@@ -0,0 +1,115 @@
@props(['name' => 'nationality', 'id' => 'nationality', 'value' => '', 'required' => false, 'error' => null])
<select id="{{ $id }}"
class="form-select nationality-select @error($name) is-invalid @enderror"
name="{{ $name }}"
{{ $required ? 'required' : '' }}>
<option value="">Select Nationality</option>
</select>
@if($error)
<span class="invalid-feedback" role="alert">
<strong>{{ $error }}</strong>
</span>
@endif
@once
@push('scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
// Country data for nationality
const countries = [
{ name: 'United States', flagCode: 'us' },
{ name: 'Canada', flagCode: 'ca' },
{ name: 'United Kingdom', flagCode: 'gb' },
{ name: 'United Arab Emirates', flagCode: 'ae' },
{ name: 'Saudi Arabia', flagCode: 'sa' },
{ name: 'Qatar', flagCode: 'qa' },
{ name: 'Kuwait', flagCode: 'kw' },
{ name: 'Bahrain', flagCode: 'bh' },
{ name: 'Oman', flagCode: 'om' },
{ name: 'Egypt', flagCode: 'eg' },
{ name: 'India', flagCode: 'in' },
{ name: 'Pakistan', flagCode: 'pk' },
{ name: 'Bangladesh', flagCode: 'bd' },
{ name: 'Malaysia', flagCode: 'my' },
{ name: 'Singapore', flagCode: 'sg' },
{ name: 'Japan', flagCode: 'jp' },
{ name: 'China', flagCode: 'cn' },
{ name: 'South Korea', flagCode: 'kr' },
{ name: 'Australia', flagCode: 'au' },
{ name: 'Germany', flagCode: 'de' },
{ name: 'France', flagCode: 'fr' },
{ name: 'Italy', flagCode: 'it' },
{ name: 'Spain', flagCode: 'es' },
{ name: 'Netherlands', flagCode: 'nl' },
{ name: 'Sweden', flagCode: 'se' },
{ name: 'Norway', flagCode: 'no' },
{ name: 'Denmark', flagCode: 'dk' },
{ name: 'Finland', flagCode: 'fi' },
{ name: 'Switzerland', flagCode: 'ch' },
{ name: 'Austria', flagCode: 'at' },
{ name: 'Poland', flagCode: 'pl' },
{ name: 'Czech Republic', flagCode: 'cz' },
{ name: 'Hungary', flagCode: 'hu' },
{ name: 'Romania', flagCode: 'ro' },
{ name: 'Greece', flagCode: 'gr' },
{ name: 'Turkey', flagCode: 'tr' },
{ name: 'Russia', flagCode: 'ru' },
{ name: 'Brazil', flagCode: 'br' },
{ name: 'Mexico', flagCode: 'mx' },
{ name: 'Argentina', flagCode: 'ar' },
{ name: 'Chile', flagCode: 'cl' },
{ name: 'Colombia', flagCode: 'co' },
{ name: 'South Africa', flagCode: 'za' },
{ name: 'Nigeria', flagCode: 'ng' },
{ name: 'Kenya', flagCode: 'ke' },
{ name: 'Sri Lanka', flagCode: 'lk' },
{ name: 'Vietnam', flagCode: 'vn' },
{ name: 'Thailand', flagCode: 'th' },
{ name: 'Indonesia', flagCode: 'id' },
{ name: 'Philippines', flagCode: 'ph' },
{ name: 'New Zealand', flagCode: 'nz' },
{ name: 'Portugal', flagCode: 'pt' },
{ name: 'Ireland', flagCode: 'ie' },
{ name: 'Israel', flagCode: 'il' },
{ name: 'Jordan', flagCode: 'jo' },
{ name: 'Lebanon', flagCode: 'lb' },
{ name: 'Iraq', flagCode: 'iq' },
];
// Initialize all nationality dropdowns on the page
document.querySelectorAll('.nationality-select').forEach(function(selectElement) {
if (typeof $ !== 'undefined' && $.fn.select2) {
const $select = $(selectElement);
$select.select2({
data: countries.map(country => ({
id: country.name,
text: country.name,
flagCode: country.flagCode
})),
templateResult: function(data) {
if (!data.id) return data.text;
return $(`<span><span class="fi fi-${data.flagCode} me-2"></span> ${data.text}</span>`);
},
templateSelection: function(data) {
if (!data.id) return data.text;
return $(`<span><span class="fi fi-${data.flagCode} me-2"></span> ${data.text}</span>`);
},
placeholder: 'Select Nationality',
allowClear: true,
width: '100%'
});
// Restore value if provided
const initialValue = selectElement.getAttribute('data-value') || '{{ $value }}';
if (initialValue) {
$select.val(initialValue).trigger('change');
}
}
});
});
</script>
@endpush
@endonce
@@ -0,0 +1,92 @@
@props(['name' => 'timezone', 'id' => 'timezone', 'value' => '', 'required' => false, 'error' => null])
<div class="mb-3">
<label for="{{ $id }}" class="form-label">Timezone</label>
<select id="{{ $id }}"
class="form-select timezone-select @error($name) is-invalid @enderror"
name="{{ $name }}"
{{ $required ? 'required' : '' }}>
<option value="">Select Timezone</option>
</select>
@if($error)
<span class="invalid-feedback" role="alert">
<strong>{{ $error }}</strong>
</span>
@endif
</div>
@once
@push('scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
// Load countries from JSON file
fetch('/data/countries.json')
.then(response => response.json())
.then(countries => {
const selectElement = document.getElementById('{{ $id }}');
if (!selectElement) return;
// Get unique timezones
const uniqueTimezones = {};
countries.forEach(country => {
if (!uniqueTimezones[country.timezone]) {
uniqueTimezones[country.timezone] = {
timezone: country.timezone,
flag: country.flag,
name: country.name
};
}
}
});
// Populate dropdown
Object.values(uniqueTimezones).forEach(timezoneData => {
const option = document.createElement('option');
option.value = timezoneData.timezone;
option.textContent = `${timezoneData.name} (${timezoneData.timezone})`;
option.setAttribute('data-flag', timezoneData.flag);
selectElement.appendChild(option);
});
// Set initial value if provided
const initialValue = '{{ $value }}';
if (initialValue) {
selectElement.value = initialValue;
}
// Initialize Select2 for searchable dropdown
if (typeof $ !== 'undefined' && $.fn.select2) {
$(selectElement).select2({
templateResult: function(state) {
if (!state.id) {
return state.text;
}
const option = $(state.element);
const flagCode = option.data('flag');
return $(`<span><span class="fi fi-${flagCode} me-2"></span>${state.text}</span>`);
},
templateSelection: function(state) {
if (!state.id) {
return state.text;
}
const option = $(state.element);
const flagCode = option.data('flag');
return $(`<span><span class="fi fi-${flagCode} me-2"></span>${state.text}</span>`);
},
width: '100%'
});
}
})
.catch(error => console.error('Error loading countries:', error));
});
</script>
@endpush
@push('styles')
<style>
.timezone-select {
background-size: 20px 15px;
}
</style>
@endpush
@endonce
@@ -0,0 +1,105 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Reset Password</title>
<style>
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
background-color: #f8f9fa;
margin: 0;
padding: 20px;
}
.container {
max-width: 600px;
margin: 0 auto;
background-color: #ffffff;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.header {
background-color: #0d6efd;
padding: 30px;
text-align: center;
}
.header h1 {
color: #ffffff;
margin: 0;
font-size: 24px;
font-weight: 600;
}
.content {
padding: 40px 30px;
}
.content h2 {
color: #333333;
font-size: 20px;
margin-top: 0;
margin-bottom: 20px;
}
.content p {
color: #666666;
line-height: 1.6;
margin-bottom: 20px;
}
.button-container {
text-align: center;
margin: 30px 0;
}
.button {
display: inline-block;
background-color: #0d6efd;
color: #ffffff;
text-decoration: none;
padding: 12px 30px;
border-radius: 5px;
font-weight: 500;
font-size: 16px;
border: none;
cursor: pointer;
}
.button:hover {
background-color: #0b5ed7;
}
.footer {
background-color: #f8f9fa;
padding: 20px 30px;
text-align: center;
border-top: 1px solid #e9ecef;
}
.footer p {
color: #999999;
font-size: 12px;
margin: 0;
}
.footer a {
color: #0d6efd;
text-decoration: none;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>{{ config('app.name', 'Club SaaS') }}</h1>
</div>
<div class="content">
<h2>Reset Your Password</h2>
<p>Hello,</p>
<p>You are receiving this email because we received a password reset request for your account.</p>
<p>This password reset link will expire in 60 minutes.</p>
<div class="button-container">
<a href="{{ $url }}" class="button">Reset Password</a>
</div>
<p>If you did not request a password reset, no further action is required.</p>
</div>
<div class="footer">
<p>&copy; {{ date('Y') }} {{ config('app.name', 'Club SaaS') }}. All rights reserved.</p>
</div>
</div>
</body>
</html>
+171
View File
@@ -0,0 +1,171 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Welcome to {{ config('app.name', 'Club SaaS') }}</title>
<style>
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
background-color: #f8f9fa;
margin: 0;
padding: 20px;
}
.container {
max-width: 600px;
margin: 0 auto;
background-color: #ffffff;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.header {
padding: 40px 30px;
text-align: center;
background: linear-gradient(135deg, {{ $user->gender == 'm' ? '#0d6efd 0%, #0a58ca 100%' : '#d63384 0%, #a61e4d 100%' }});
}
.header h1 {
color: #ffffff;
margin: 0;
font-size: 28px;
font-weight: 600;
}
.header p {
color: rgba(255, 255, 255, 0.9);
margin: 10px 0 0 0;
font-size: 16px;
}
.content {
padding: 40px 30px;
}
.welcome-section {
text-align: center;
margin-bottom: 30px;
}
.welcome-section h2 {
color: {{ $user->gender == 'm' ? '#0d6efd' : '#d63384' }};
font-size: 24px;
margin-top: 0;
margin-bottom: 10px;
}
.welcome-section p {
color: #666666;
line-height: 1.6;
margin-bottom: 20px;
}
.info-box {
background-color: {{ $user->gender == 'm' ? 'rgba(13, 110, 253, 0.05)' : 'rgba(214, 51, 132, 0.05)' }};
border-left: 4px solid {{ $user->gender == 'm' ? '#0d6efd' : '#d63384' }};
padding: 20px;
margin: 20px 0;
border-radius: 5px;
}
.info-box h3 {
color: {{ $user->gender == 'm' ? '#0d6efd' : '#d63384' }};
font-size: 18px;
margin-top: 0;
margin-bottom: 15px;
}
.info-box p {
color: #666666;
line-height: 1.6;
margin: 0 0 10px 0;
}
.info-box strong {
color: #333333;
}
.button-container {
text-align: center;
margin: 30px 0;
}
.button {
display: inline-block;
background-color: {{ $user->gender == 'm' ? '#0d6efd' : '#d63384' }};
color: #ffffff;
text-decoration: none;
padding: 14px 40px;
border-radius: 5px;
font-weight: 500;
font-size: 16px;
border: none;
cursor: pointer;
}
.button:hover {
background-color: {{ $user->gender == 'm' ? '#0b5ed7' : '#b02a5c' }};
}
.footer {
background-color: #f8f9fa;
padding: 20px 30px;
text-align: center;
border-top: 1px solid #e9ecef;
}
.footer p {
color: #999999;
font-size: 12px;
margin: 0;
}
.footer a {
color: {{ $user->gender == 'm' ? '#0d6efd' : '#d63384' }};
text-decoration: none;
}
.divider {
height: 1px;
background-color: #e9ecef;
margin: 30px 0;
}
.greeting {
font-size: 18px;
color: #333333;
margin-bottom: 20px;
}
.greeting strong {
color: {{ $user->gender == 'm' ? '#0d6efd' : '#d63384' }};
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>{{ config('app.name', 'Club SaaS') }}</h1>
<p>Welcome to the Family</p>
</div>
<div class="content">
<div class="welcome-section">
<p class="greeting">Dear <strong>{{ $user->full_name }}</strong>,</p>
<h2>Welcome to the Family!</h2>
<p>We are thrilled to have you join our community. Your account has been successfully created and you are now part of our family.</p>
</div>
@if($guardian && $relationship)
<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>
@if($user->birthdate)
<p><strong>Birthdate:</strong> {{ \Carbon\Carbon::parse($user->birthdate)->format('F j, Y') }}</p>
@endif
</div>
@endif
<div class="divider"></div>
<p>We're excited to have you with us. If you have any questions or need assistance, please don't hesitate to reach out to your guardian or our support team.</p>
<div class="button-container">
<a href="{{ url('/login') }}" class="button">Access Your Account</a>
</div>
<p style="text-align: center; color: #999999; font-size: 14px; margin-top: 30px;">
If you have any questions, feel free to contact us at any time.
</p>
</div>
<div class="footer">
<p>&copy; {{ date('Y') }} {{ config('app.name', 'Club SaaS') }}. All rights reserved.</p>
<p style="margin-top: 10px;">
<a href="{{ url('/') }}">Visit Website</a> |
<a href="mailto:{{ config('mail.from.address') }}">Contact Support</a>
</p>
</div>
</div>
</body>
</html>
@@ -0,0 +1,161 @@
@extends('layouts.app')
@section('content')
<!-- Flag Icons CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/css/flag-icons.min.css">
<!-- Select2 CSS -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/select2.min.css" rel="stylesheet" />
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card shadow">
<div class="card-header bg-white">
<h3 class="mb-0">Example Form with Reusable Components</h3>
</div>
<div class="card-body p-4">
<form method="POST" action="#">
@csrf
<div class="row">
<div class="col-md-6">
<!-- Example 1: Mobile Number with Country Code -->
<div class="mb-3">
<label for="mobile_number" class="form-label">Mobile Number</label>
<x-country-code-dropdown
name="country_code"
id="country_code"
:value="old('country_code', '+971')"
:required="true"
:error="$errors->first('country_code')">
<input id="mobile_number" type="tel"
class="form-control @error('mobile_number') is-invalid @enderror"
name="mobile_number"
value="{{ old('mobile_number') }}"
required
placeholder="Phone number">
</x-country-code-dropdown>
@error('mobile_number')
<span class="invalid-feedback d-block" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
<!-- Example 2: Emergency Contact with Country Code -->
<div class="mb-3">
<label for="emergency_number" class="form-label">Emergency Contact</label>
<x-country-code-dropdown
name="emergency_country_code"
id="emergency_country_code"
:value="old('emergency_country_code', '+971')"
:required="false"
:error="$errors->first('emergency_country_code')">
<input id="emergency_number" type="tel"
class="form-control"
name="emergency_number"
value="{{ old('emergency_number') }}"
placeholder="Emergency phone number">
</x-country-code-dropdown>
</div>
</div>
<div class="col-md-6">
<!-- Example 3: Nationality Dropdown -->
<div class="mb-3">
<label for="nationality" class="form-label">Nationality</label>
<x-nationality-dropdown
name="nationality"
id="nationality"
:value="old('nationality')"
:required="true"
:error="$errors->first('nationality')" />
</div>
<!-- Example 4: Second Nationality (Optional) -->
<div class="mb-3">
<label for="second_nationality" class="form-label">Second Nationality (Optional)</label>
<x-nationality-dropdown
name="second_nationality"
id="second_nationality"
:value="old('second_nationality')"
:required="false"
:error="$errors->first('second_nationality')" />
</div>
</div>
</div>
<div class="alert alert-info mt-3">
<h5>Component Features:</h5>
<ul class="mb-0">
<li><strong>Country Code Dropdown:</strong> Bootstrap-based with flag icons and search</li>
<li><strong>Nationality Dropdown:</strong> Select2-based with flag icons and search</li>
<li>Both components preserve values on validation errors</li>
<li>Both components support required/optional fields</li>
<li>Both components display validation errors</li>
<li>Multiple instances can be used on the same page</li>
</ul>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary btn-lg">
Submit Form
</button>
</div>
</form>
</div>
</div>
<!-- Usage Instructions -->
<div class="card shadow mt-4">
<div class="card-header bg-white">
<h4 class="mb-0">How to Use These Components</h4>
</div>
<div class="card-body">
<h5>1. Country Code Dropdown</h5>
<pre class="bg-light p-3 rounded"><code>&lt;x-country-code-dropdown
name="country_code"
id="country_code"
:value="old('country_code', '+971')"
:required="true"
:error="$errors->first('country_code')"&gt;
&lt;input type="tel" class="form-control" name="mobile_number" placeholder="Phone number"&gt;
&lt;/x-country-code-dropdown&gt;</code></pre>
<h5 class="mt-4">2. Nationality Dropdown</h5>
<pre class="bg-light p-3 rounded"><code>&lt;x-nationality-dropdown
name="nationality"
id="nationality"
:value="old('nationality')"
:required="true"
:error="$errors->first('nationality')" /&gt;</code></pre>
<h5 class="mt-4">3. Required Dependencies</h5>
<pre class="bg-light p-3 rounded"><code>&lt;!-- CSS --&gt;
&lt;link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/css/flag-icons.min.css"&gt;
&lt;link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/select2.min.css" rel="stylesheet" /&gt;
&lt;!-- JS --&gt;
&lt;script src="https://code.jquery.com/jquery-3.6.0.min.js"&gt;&lt;/script&gt;
&lt;script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/select2.min.js"&gt;&lt;/script&gt;
&lt;!-- Component Scripts --&gt;
@stack('styles')
@stack('scripts')</code></pre>
</div>
</div>
</div>
</div>
</div>
<!-- jQuery (required for Select2) -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- Select2 JS -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/select2.min.js"></script>
<!-- Load component scripts -->
@stack('styles')
@stack('scripts')
@endsection
+21 -9
View File
@@ -33,8 +33,8 @@
<label for="gender" class="form-label">Gender</label>
<select class="form-select @error('gender') is-invalid @enderror" id="gender" name="gender" required>
<option value="">Select Gender</option>
<option value="male" {{ old('gender') == 'male' ? 'selected' : '' }}>Male</option>
<option value="female" {{ old('gender') == 'female' ? 'selected' : '' }}>Female</option>
<option value="m" {{ old('gender') == 'm' ? 'selected' : '' }}>Male</option>
<option value="f" {{ old('gender') == 'f' ? 'selected' : '' }}>Female</option>
</select>
@error('gender')
<div class="invalid-feedback">{{ $message }}</div>
@@ -51,18 +51,30 @@
<div class="row mb-3">
<div class="col-md-6">
<label for="blood_type" class="form-label">Blood Type <span class="text-muted">(Optional)</span></label>
<input type="text" class="form-control @error('blood_type') is-invalid @enderror" id="blood_type" name="blood_type" value="{{ old('blood_type') }}">
<label for="blood_type" class="form-label">Blood Type</label>
<select class="form-select @error('blood_type') is-invalid @enderror" id="blood_type" name="blood_type">
<option value="">Select Blood Type</option>
<option value="A+" {{ old('blood_type') == 'A+' ? 'selected' : '' }}>A+</option>
<option value="A-" {{ old('blood_type') == 'A-' ? 'selected' : '' }}>A-</option>
<option value="B+" {{ old('blood_type') == 'B+' ? 'selected' : '' }}>B+</option>
<option value="B-" {{ old('blood_type') == 'B-' ? 'selected' : '' }}>B-</option>
<option value="AB+" {{ old('blood_type') == 'AB+' ? 'selected' : '' }}>AB+</option>
<option value="AB-" {{ old('blood_type') == 'AB-' ? 'selected' : '' }}>AB-</option>
<option value="O+" {{ old('blood_type') == 'O+' ? 'selected' : '' }}>O+</option>
<option value="O-" {{ old('blood_type') == 'O-' ? 'selected' : '' }}>O-</option>
<option value="Unknown" {{ old('blood_type') == 'Unknown' ? 'selected' : '' }}>Unknown</option>
</select>
@error('blood_type')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="col-md-6">
<label for="nationality" class="form-label">Nationality</label>
<input type="text" class="form-control @error('nationality') is-invalid @enderror" id="nationality" name="nationality" value="{{ old('nationality') }}" required>
@error('nationality')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
<x-country-dropdown
name="nationality"
id="nationality"
:value="old('nationality')"
:required="true"
:error="$errors->first('nationality')" />
</div>
</div>
+311 -39
View File
@@ -12,63 +12,265 @@
</div>
<!-- Family Members Card Grid -->
<div class="row row-cols-1 row-cols-md-3 g-4 mb-5">
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-4 g-4 mb-5">
<!-- Current User Card -->
<div class="col">
<div class="card h-100 shadow-sm">
<div class="card-body text-center">
<div class="mb-3">
<img src="{{ $user->media_gallery[0] ?? 'https://via.placeholder.com/150' }}"
class="rounded-circle" alt="{{ $user->full_name }}"
width="100" height="100">
<a href="{{ route('profile.show') }}" class="text-decoration-none">
<div class="card h-100 shadow-sm border-0 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="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;">
@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-center text-white fw-bold fs-4" style="background: linear-gradient(135deg, {{ $user->gender == 'm' ? '#0d6efd 0%, #0a58ca 100%' : '#d63384 0%, #a61e4d 100%' }});">
{{ strtoupper(substr($user->full_name, 0, 1)) }}
</div>
@endif
</div>
</div>
<div class="flex-grow-1 min-w-0">
<h5 class="fw-bold mb-2 text-truncate">{{ $user->full_name }}</h5>
<div class="d-flex flex-wrap gap-2">
<span class="badge {{ $user->gender == 'm' ? 'bg-primary' : 'bg-danger' }}">Adult</span>
<span class="badge bg-success">Active</span>
</div>
</div>
</div>
<h5 class="card-title">{{ $user->full_name }}</h5>
<p class="card-text text-muted">
Age: {{ $user->age }} ({{ $user->life_stage }})
</p>
<p class="card-text">
<small class="text-muted">{{ $user->horoscope }}</small>
</p>
<a href="{{ route('profile.edit') }}" class="btn btn-primary">
<i class="bi bi-pencil"></i> Edit Profile
</a>
</div>
</div>
<!-- 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">{{ $user->mobile }}</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>
<span class="fw-medium text-truncate">{{ $user->email }}</span>
</div>
@endif
</div>
<!-- Details -->
<div class="px-4 py-3 flex-grow-1">
<div class="row g-3 mb-3">
<div class="col-6">
<div class="small text-muted text-uppercase fw-medium mb-1" style="font-size: 0.7rem; letter-spacing: 0.5px;">Gender</div>
<div class="fw-semibold text-capitalize">{{ $user->gender == 'm' ? 'Male' : 'Female' }}</div>
</div>
<div class="col-6">
<div class="small text-muted text-uppercase fw-medium mb-1" style="font-size: 0.7rem; letter-spacing: 0.5px;">Age</div>
<div class="fw-semibold">{{ $user->age }} years</div>
</div>
</div>
<div class="row g-3 mb-3">
<div class="col-6">
<div class="small text-muted text-uppercase fw-medium mb-1" style="font-size: 0.7rem; letter-spacing: 0.5px;">Nationality</div>
<div class="fw-semibold fs-5 nationality-display" data-iso3="{{ $user->nationality }}">{{ $user->nationality }}</div>
</div>
<div class="col-6">
<div class="small text-muted text-uppercase fw-medium mb-1" style="font-size: 0.7rem; letter-spacing: 0.5px;">Horoscope</div>
<div class="fw-semibold">
@php
$horoscopeSymbols = [
'Aries' => '♈',
'Taurus' => '♉',
'Gemini' => '♊',
'Cancer' => '♋',
'Leo' => '♌',
'Virgo' => '♍',
'Libra' => '♎',
'Scorpio' => '♏',
'Sagittarius' => '♐',
'Capricorn' => '♑',
'Aquarius' => '♒',
'Pisces' => '♓'
];
$horoscope = $user->horoscope ?? 'N/A';
$symbol = $horoscopeSymbols[$horoscope] ?? '';
@endphp
{{ $symbol }} {{ $horoscope }}
</div>
</div>
</div>
<div class="pt-2 border-top">
<div class="d-flex justify-content-between align-items-center small mb-2">
<span class="text-muted fw-medium">Next Birthday</span>
<span class="fw-semibold {{ $user->gender == 'm' ? 'text-primary' : 'text-danger' }}">
{{ $user->birthdate->copy()->year(now()->year)->isFuture()
? $user->birthdate->copy()->year(now()->year)->diffForHumans(['parts' => 2, 'syntax' => \Carbon\CarbonInterface::DIFF_ABSOLUTE])
: $user->birthdate->copy()->year(now()->year + 1)->diffForHumans(['parts' => 2, 'syntax' => \Carbon\CarbonInterface::DIFF_ABSOLUTE]) }}
</span>
</div>
<div class="d-flex justify-content-between align-items-center small">
<span class="text-muted fw-medium">Member Since</span>
<span class="fw-semibold">{{ $user->created_at->format('d/m/Y') }}</span>
</div>
</div>
</div>
</div>
</a>
</div>
<!-- Dependents Cards -->
@foreach($dependents as $relationship)
<div class="col">
<div class="card h-100 shadow-sm">
<div class="card-body text-center">
<div class="mb-3">
<img src="{{ $relationship->dependent->media_gallery[0] ?? 'https://via.placeholder.com/150' }}"
class="rounded-circle" alt="{{ $relationship->dependent->full_name }}"
width="100" height="100">
<a href="{{ route('family.show', $relationship->dependent->id) }}" class="text-decoration-none">
<div class="card h-100 shadow-sm border-0 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="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;">
@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-center text-white fw-bold fs-4" style="background: linear-gradient(135deg, {{ $relationship->dependent->gender == 'm' ? '#0d6efd 0%, #0a58ca 100%' : '#d63384 0%, #a61e4d 100%' }});">
{{ strtoupper(substr($relationship->dependent->full_name, 0, 1)) }}
</div>
@endif
</div>
</div>
<div class="flex-grow-1 min-w-0">
<h5 class="fw-bold mb-2 text-truncate">{{ $relationship->dependent->full_name }}</h5>
<div class="d-flex flex-wrap gap-2">
@php
$age = $relationship->dependent->age;
$ageGroup = 'Adult';
if ($age < 2) {
$ageGroup = 'Infant';
} elseif ($age < 4) {
$ageGroup = 'Toddler';
} elseif ($age < 6) {
$ageGroup = 'Preschooler';
} elseif ($age < 13) {
$ageGroup = 'Child';
} elseif ($age < 20) {
$ageGroup = 'Teenager';
} elseif ($age < 40) {
$ageGroup = 'Young Adult';
} elseif ($age < 60) {
$ageGroup = 'Adult';
} else {
$ageGroup = 'Senior';
}
@endphp
<span class="badge {{ $relationship->dependent->gender == 'm' ? 'bg-primary' : 'bg-danger' }}">{{ $ageGroup }}</span>
<span class="badge bg-success">Active</span>
</div>
</div>
</div>
<h5 class="card-title">{{ $relationship->dependent->full_name }}</h5>
<p class="card-text text-muted">
Age: {{ $relationship->dependent->age }} ({{ $relationship->dependent->life_stage }})
</p>
<span class="badge bg-secondary">{{ ucfirst($relationship->relationship_type) }}</span>
</div>
<div class="card-footer bg-transparent border-top-0 text-center">
<div class="btn-group" role="group">
<a href="{{ route('family.edit', $relationship->dependent->id) }}" class="btn btn-sm btn-outline-secondary">
<i class="bi bi-pencil"></i> Edit
</a>
<a href="{{ route('family.show', $relationship->dependent->id) }}" class="btn btn-sm btn-outline-primary">
<i class="bi bi-eye"></i> View
</a>
<!-- Sponsor/Guardian Info -->
<div class="px-4 py-2 {{ $relationship->dependent->gender == 'm' ? 'bg-primary' : 'bg-danger' }} bg-opacity-10 border-bottom">
<div class="d-flex align-items-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' }}">
{{ ucfirst($relationship->relationship_type) }}: {{ $user->full_name }}
</span>
</div>
</div>
<!-- Contact Info -->
<div class="px-4 py-3 bg-light 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">{{ $relationship->dependent->mobile }}</span>
</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">{{ $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>
<span class="fw-medium text-truncate">{{ $relationship->dependent->email }}</span>
</div>
@elseif($user->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>
<span class="fw-medium text-truncate">{{ $user->email }}</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
</div>
<!-- Details -->
<div class="px-4 py-3 flex-grow-1">
<div class="row g-3 mb-3">
<div class="col-6">
<div class="small text-muted text-uppercase fw-medium mb-1" style="font-size: 0.7rem; letter-spacing: 0.5px;">Gender</div>
<div class="fw-semibold text-capitalize">{{ $relationship->dependent->gender == 'm' ? 'Male' : 'Female' }}</div>
</div>
<div class="col-6">
<div class="small text-muted text-uppercase fw-medium mb-1" style="font-size: 0.7rem; letter-spacing: 0.5px;">Age</div>
<div class="fw-semibold">{{ $relationship->dependent->age }} years</div>
</div>
</div>
<div class="row g-3 mb-3">
<div class="col-6">
<div class="small text-muted text-uppercase fw-medium mb-1" style="font-size: 0.7rem; letter-spacing: 0.5px;">Nationality</div>
<div class="fw-semibold fs-5 nationality-display" data-iso3="{{ $relationship->dependent->nationality }}">{{ $relationship->dependent->nationality }}</div>
</div>
<div class="col-6">
<div class="small text-muted text-uppercase fw-medium mb-1" style="font-size: 0.7rem; letter-spacing: 0.5px;">Horoscope</div>
<div class="fw-semibold">
@php
$horoscopeSymbols = [
'Aries' => '♈',
'Taurus' => '♉',
'Gemini' => '♊',
'Cancer' => '♋',
'Leo' => '♌',
'Virgo' => '♍',
'Libra' => '♎',
'Scorpio' => '♏',
'Sagittarius' => '♐',
'Capricorn' => '♑',
'Aquarius' => '♒',
'Pisces' => '♓'
];
$horoscope = $relationship->dependent->horoscope ?? 'N/A';
$symbol = $horoscopeSymbols[$horoscope] ?? '';
@endphp
{{ $symbol }} {{ $horoscope }}
</div>
</div>
</div>
<div class="pt-2 border-top">
<div class="d-flex justify-content-between align-items-center small mb-2">
<span class="text-muted fw-medium">Next Birthday</span>
<span class="fw-semibold {{ $relationship->dependent->gender == 'm' ? 'text-primary' : 'text-danger' }}">
{{ $relationship->dependent->birthdate->copy()->year(now()->year)->isFuture()
? $relationship->dependent->birthdate->copy()->year(now()->year)->diffForHumans(['parts' => 2, 'syntax' => \Carbon\CarbonInterface::DIFF_ABSOLUTE])
: $relationship->dependent->birthdate->copy()->year(now()->year + 1)->diffForHumans(['parts' => 2, 'syntax' => \Carbon\CarbonInterface::DIFF_ABSOLUTE]) }}
</span>
</div>
<div class="d-flex justify-content-between align-items-center small">
<span class="text-muted fw-medium">Member Since</span>
<span class="fw-semibold">{{ $relationship->dependent->created_at->format('d/m/Y') }}</span>
</div>
</div>
</div>
</div>
</div>
</a>
</div>
@endforeach
<!-- Add New Family Member Card -->
<div class="col">
<div class="card h-100 shadow-sm border-dashed">
<div class="card h-100 shadow-sm border-dashed add-card">
<a href="{{ route('family.create') }}" class="card-body text-center text-decoration-none d-flex flex-column justify-content-center align-items-center" style="height: 100%;">
<div class="mb-3">
<i class="bi bi-plus-circle" style="font-size: 3rem;"></i>
@@ -149,5 +351,75 @@
border-width: 2px !important;
border-color: #dee2e6 !important;
}
/* Family Card Hover Effects */
.family-card {
transition: all 0.3s ease-in-out;
cursor: pointer;
}
.family-card:hover {
transform: translateY(-8px);
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15) !important;
}
.family-card:hover .rounded-circle {
transform: scale(1.1);
transition: transform 0.3s ease-in-out;
}
/* Remove underline from card links */
a.text-decoration-none:hover .family-card {
text-decoration: none;
}
/* Add Card Hover Effects */
.add-card {
transition: all 0.3s ease-in-out;
}
.add-card:hover {
transform: translateY(-8px);
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15) !important;
border-color: #0d6efd !important;
}
.add-card:hover .bi-plus-circle {
color: #0d6efd;
transition: color 0.3s ease-in-out;
}
.add-card:hover h5 {
color: #0d6efd;
transition: color 0.3s ease-in-out;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Load countries from JSON file
fetch('/data/countries.json')
.then(response => response.json())
.then(countries => {
// Convert all nationality displays from ISO3 to country name with flag
document.querySelectorAll('.nationality-display').forEach(element => {
const iso3Code = element.getAttribute('data-iso3');
if (!iso3Code) return;
const country = countries.find(c => c.iso3 === iso3Code);
if (country) {
// Get flag emoji from ISO2 code
const flagEmoji = country.iso2
.toUpperCase()
.split('')
.map(char => String.fromCodePoint(127397 + char.charCodeAt(0)))
.join('');
element.textContent = `${flagEmoji} ${country.iso2.toUpperCase()}`;
}
});
})
.catch(error => console.error('Error loading countries:', error));
});
</script>
@endsection
+21 -9
View File
@@ -34,8 +34,8 @@
<label for="gender" class="form-label">Gender</label>
<select class="form-select @error('gender') is-invalid @enderror" id="gender" name="gender" required>
<option value="">Select Gender</option>
<option value="male" {{ old('gender', $relationship->dependent->gender) == 'male' ? 'selected' : '' }}>Male</option>
<option value="female" {{ old('gender', $relationship->dependent->gender) == 'female' ? 'selected' : '' }}>Female</option>
<option value="m" {{ old('gender', $relationship->dependent->gender) == 'm' ? 'selected' : '' }}>Male</option>
<option value="f" {{ old('gender', $relationship->dependent->gender) == 'f' ? 'selected' : '' }}>Female</option>
</select>
@error('gender')
<div class="invalid-feedback">{{ $message }}</div>
@@ -52,18 +52,30 @@
<div class="row mb-3">
<div class="col-md-6">
<label for="blood_type" class="form-label">Blood Type <span class="text-muted">(Optional)</span></label>
<input type="text" class="form-control @error('blood_type') is-invalid @enderror" id="blood_type" name="blood_type" value="{{ old('blood_type', $relationship->dependent->blood_type) }}">
<label for="blood_type" class="form-label">Blood Type</label>
<select class="form-select @error('blood_type') is-invalid @enderror" id="blood_type" name="blood_type">
<option value="">Select Blood Type</option>
<option value="A+" {{ old('blood_type', $relationship->dependent->blood_type) == 'A+' ? 'selected' : '' }}>A+</option>
<option value="A-" {{ old('blood_type', $relationship->dependent->blood_type) == 'A-' ? 'selected' : '' }}>A-</option>
<option value="B+" {{ old('blood_type', $relationship->dependent->blood_type) == 'B+' ? 'selected' : '' }}>B+</option>
<option value="B-" {{ old('blood_type', $relationship->dependent->blood_type) == 'B-' ? 'selected' : '' }}>B-</option>
<option value="AB+" {{ old('blood_type', $relationship->dependent->blood_type) == 'AB+' ? 'selected' : '' }}>AB+</option>
<option value="AB-" {{ old('blood_type', $relationship->dependent->blood_type) == 'AB-' ? 'selected' : '' }}>AB-</option>
<option value="O+" {{ old('blood_type', $relationship->dependent->blood_type) == 'O+' ? 'selected' : '' }}>O+</option>
<option value="O-" {{ old('blood_type', $relationship->dependent->blood_type) == 'O-' ? 'selected' : '' }}>O-</option>
<option value="Unknown" {{ old('blood_type', $relationship->dependent->blood_type) == 'Unknown' ? 'selected' : '' }}>Unknown</option>
</select>
@error('blood_type')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="col-md-6">
<label for="nationality" class="form-label">Nationality</label>
<input type="text" class="form-control @error('nationality') is-invalid @enderror" id="nationality" name="nationality" value="{{ old('nationality', $relationship->dependent->nationality) }}" required>
@error('nationality')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
<x-country-dropdown
name="nationality"
id="nationality"
:value="old('nationality', $relationship->dependent->nationality)"
:required="true"
:error="$errors->first('nationality')" />
</div>
</div>
+816 -87
View File
@@ -2,91 +2,484 @@
@section('content')
<div class="container py-4">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card shadow-sm">
<div class="card-header bg-white d-flex justify-content-between align-items-center">
<h4 class="mb-0">Family Member Details</h4>
<a href="{{ route('family.dashboard') }}" class="btn btn-outline-secondary btn-sm">
<i class="bi bi-arrow-left"></i> Back to Family
</a>
<!-- Header -->
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h2 class="fw-bold mb-1">Member Profile</h2>
<p class="text-muted mb-0">Comprehensive member information and analytics</p>
</div>
<a href="{{ route('family.dashboard') }}" class="btn btn-outline-secondary">
<i class="bi bi-arrow-left me-2"></i>Back to Family
</a>
</div>
<!-- Profile Card -->
<div class="card shadow-sm border-0 mb-4 overflow-hidden">
<div class="d-flex">
<!-- Profile Picture -->
<div style="width: 180px; min-height: 250px;">
@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" style="font-size: 3rem; background: linear-gradient(135deg, {{ $relationship->dependent->gender == 'm' ? '#0d6efd 0%, #0a58ca 100%' : '#d63384 0%, #a61e4d 100%' }});">
{{ strtoupper(substr($relationship->dependent->full_name, 0, 1)) }}
</div>
@endif
</div>
<!-- Profile Info -->
<div class="flex-grow-1 p-4">
<div class="d-flex justify-content-between align-items-start mb-2">
<h3 class="fw-bold mb-0">{{ $relationship->dependent->full_name }}</h3>
<button class="btn btn-primary btn-sm">
<i class="bi bi-person-plus me-1"></i>Follow
</button>
</div>
<div class="card-body">
<div class="text-center mb-4">
<img src="{{ $relationship->dependent->media_gallery[0] ?? 'https://via.placeholder.com/150' }}"
class="rounded-circle mb-3" alt="{{ $relationship->dependent->full_name }}"
width="120" height="120">
<h3>{{ $relationship->dependent->full_name }}</h3>
<span class="badge bg-secondary">{{ ucfirst($relationship->relationship_type) }}</span>
@if($relationship->is_billing_contact)
<span class="badge bg-info ms-2">Billing Contact</span>
@endif
</div>
<p class="text-muted fst-italic mb-3">"Every rep brings me closer to my best self. Consistency is my superpower!"</p>
<div class="row">
<div class="col-md-6 mb-3">
<h6 class="text-muted">Age</h6>
<p>{{ $relationship->dependent->age }} years ({{ $relationship->dependent->life_stage }})</p>
</div>
<div class="col-md-6 mb-3">
<h6 class="text-muted">Birthdate</h6>
<p>{{ $relationship->dependent->birthdate->format('F j, Y') }}</p>
</div>
<div class="col-md-6 mb-3">
<h6 class="text-muted">Gender</h6>
<p>{{ ucfirst($relationship->dependent->gender) }}</p>
</div>
<div class="col-md-6 mb-3">
<h6 class="text-muted">Horoscope</h6>
<p>{{ $relationship->dependent->horoscope }}</p>
</div>
<div class="col-md-6 mb-3">
<h6 class="text-muted">Nationality</h6>
<p>{{ $relationship->dependent->nationality }}</p>
</div>
<div class="col-md-6 mb-3">
<h6 class="text-muted">Blood Type</h6>
<p>{{ $relationship->dependent->blood_type ?? 'Not specified' }}</p>
</div>
@if($relationship->dependent->email)
<div class="col-md-6 mb-3">
<h6 class="text-muted">Email</h6>
<p>{{ $relationship->dependent->email }}</p>
</div>
@endif
@if($relationship->dependent->mobile)
<div class="col-md-6 mb-3">
<h6 class="text-muted">Mobile</h6>
<p>{{ $relationship->dependent->mobile }}</p>
</div>
@endif
</div>
<!-- Achievement Badges -->
<div class="d-flex gap-2 mb-3 flex-wrap">
<a href="#" class="border bg-white rounded px-2 py-1 text-decoration-none" style="font-size: 1rem;">🏆 <span class="fw-semibold text-dark">3</span></a>
<a href="#" class="border bg-white rounded px-2 py-1 text-decoration-none" style="font-size: 1rem;">🥇 <span class="fw-semibold text-dark">4</span></a>
<a href="#" class="border bg-white rounded px-2 py-1 text-decoration-none" style="font-size: 1rem;">🥈 <span class="fw-semibold text-dark">6</span></a>
<a href="#" class="border bg-white rounded px-2 py-1 text-decoration-none" style="font-size: 1rem;">🥉 <span class="fw-semibold text-dark">3</span></a>
<a href="#" class="border bg-white rounded px-2 py-1 text-decoration-none" style="font-size: 1rem;">🎯 <span class="fw-semibold text-dark">8</span></a>
<a href="#" class="border bg-white rounded px-2 py-1 text-decoration-none" style="font-size: 1rem;">⭐ <span class="fw-semibold text-dark">12</span></a>
</div>
<div class="d-flex justify-content-end mt-3">
<a href="{{ route('family.edit', $relationship->dependent->id) }}" class="btn btn-primary">
<i class="bi bi-pencil"></i> Edit
</a>
<!-- Status Badges -->
<div class="d-flex gap-3 mb-3 align-items-center flex-wrap">
<span class="text-muted small">
<span class="fw-semibold text-dark nationality-display" data-iso3="{{ $relationship->dependent->nationality }}">{{ $relationship->dependent->nationality }}</span>
</span>
<span class="text-muted small">
<i class="bi bi-{{ $relationship->dependent->gender == 'm' ? 'gender-male' : 'gender-female' }} me-1"></i>
<span class="fw-semibold text-dark">{{ $relationship->dependent->gender == 'm' ? 'Male' : 'Female' }}</span>
</span>
<span class="text-muted small">
<i class="bi bi-calendar-event me-1"></i>
Age <span class="fw-semibold text-dark">{{ $relationship->dependent->age }}</span>
</span>
<span class="text-muted small">
@php
$horoscopeSymbols = [
'Aries' => '♈',
'Taurus' => '♉',
'Gemini' => '♊',
'Cancer' => '♋',
'Leo' => '♌',
'Virgo' => '♍',
'Libra' => '♎',
'Scorpio' => '♏',
'Sagittarius' => '♐',
'Capricorn' => '♑',
'Aquarius' => '♒',
'Pisces' => '♓'
];
$horoscope = $relationship->dependent->horoscope ?? 'N/A';
$symbol = $horoscopeSymbols[$horoscope] ?? '';
@endphp
{{ $symbol }} <span class="fw-semibold text-dark">{{ $horoscope }}</span>
</span>
<span class="text-muted small">
<i class="bi bi-check-circle-fill text-success me-1"></i>
<span class="fw-semibold text-success">Active</span>
</span>
<span class="text-muted small">
<i class="bi bi-calendar-check me-1"></i>
Joined <span class="fw-semibold text-dark">{{ $relationship->dependent->created_at->format('F Y') }}</span>
</span>
</div>
<!-- Social Media Icons -->
<div class="d-flex gap-2 flex-wrap">
<a href="#" class="btn btn-sm btn-outline-secondary rounded-circle" style="width: 32px; height: 32px; padding: 0; display: flex; align-items: center; justify-content: center;" title="Facebook">
<i class="bi bi-facebook"></i>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary rounded-circle" style="width: 32px; height: 32px; padding: 0; display: flex; align-items: center; justify-content: center;" title="Twitter/X">
<span style="font-weight: bold; font-size: 1.2rem;">X</span>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary rounded-circle" style="width: 32px; height: 32px; padding: 0; display: flex; align-items: center; justify-content: center;" title="Instagram">
<i class="bi bi-instagram"></i>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary rounded-circle" style="width: 32px; height: 32px; padding: 0; display: flex; align-items: center; justify-content: center;" title="LinkedIn">
<i class="bi bi-linkedin"></i>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary rounded-circle" style="width: 32px; height: 32px; padding: 0; display: flex; align-items: center; justify-content: center;" title="YouTube">
<i class="bi bi-youtube"></i>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary rounded-circle" style="width: 32px; height: 32px; padding: 0; display: flex; align-items: center; justify-content: center;" title="TikTok">
<i class="bi bi-tiktok"></i>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary rounded-circle" style="width: 32px; height: 32px; padding: 0; display: flex; align-items: center; justify-content: center;" title="Snapchat">
<i class="bi bi-snapchat"></i>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary rounded-circle" style="width: 32px; height: 32px; padding: 0; display: flex; align-items: center; justify-content: center;" title="WhatsApp">
<i class="bi bi-whatsapp"></i>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary rounded-circle" style="width: 32px; height: 32px; padding: 0; display: flex; align-items: center; justify-content: center;" title="Telegram">
<i class="bi bi-telegram"></i>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary rounded-circle" style="width: 32px; height: 32px; padding: 0; display: flex; align-items: center; justify-content: center;" title="Discord">
<i class="bi bi-discord"></i>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary rounded-circle" style="width: 32px; height: 32px; padding: 0; display: flex; align-items: center; justify-content: center;" title="Reddit">
<i class="bi bi-reddit"></i>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary rounded-circle" style="width: 32px; height: 32px; padding: 0; display: flex; align-items: center; justify-content: center;" title="Pinterest">
<i class="bi bi-pinterest"></i>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary rounded-circle" style="width: 32px; height: 32px; padding: 0; display: flex; align-items: center; justify-content: center;" title="Twitch">
<i class="bi bi-twitch"></i>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary rounded-circle" style="width: 32px; height: 32px; padding: 0; display: flex; align-items: center; justify-content: center;" title="GitHub">
<i class="bi bi-github"></i>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary rounded-circle" style="width: 32px; height: 32px; padding: 0; display: flex; align-items: center; justify-content: center;" title="Spotify">
<i class="bi bi-spotify"></i>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary rounded-circle" style="width: 32px; height: 32px; padding: 0; display: flex; align-items: center; justify-content: center;" title="Skype">
<i class="bi bi-skype"></i>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary rounded-circle" style="width: 32px; height: 32px; padding: 0; display: flex; align-items: center; justify-content: center;" title="Slack">
<i class="bi bi-slack"></i>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary rounded-circle" style="width: 32px; height: 32px; padding: 0; display: flex; align-items: center; justify-content: center;" title="Medium">
<i class="bi bi-medium"></i>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary rounded-circle" style="width: 32px; height: 32px; padding: 0; display: flex; align-items: center; justify-content: center;" title="Vimeo">
<i class="bi bi-vimeo"></i>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary rounded-circle" style="width: 32px; height: 32px; padding: 0; display: flex; align-items: center; justify-content: center;" title="Messenger">
<i class="bi bi-messenger"></i>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary rounded-circle" style="width: 32px; height: 32px; padding: 0; display: flex; align-items: center; justify-content: center;" title="WeChat">
<i class="bi bi-wechat"></i>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary rounded-circle" style="width: 32px; height: 32px; padding: 0; display: flex; align-items: center; justify-content: center;" title="Line">
<i class="bi bi-line"></i>
</a>
</div>
</div>
</div>
</div>
<!-- Navigation Tabs -->
<ul class="nav nav-tabs nav-fill mb-4" id="profileTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active text-dark" id="overview-tab" data-bs-toggle="tab" data-bs-target="#overview" type="button" role="tab">
<i class="bi bi-eye me-2"></i>Overview
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link text-dark" id="attendance-tab" data-bs-toggle="tab" data-bs-target="#attendance" type="button" role="tab">
<i class="bi bi-calendar-check me-2"></i>Attendance
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link text-dark" id="health-tab" data-bs-toggle="tab" data-bs-target="#health" type="button" role="tab">
<i class="bi bi-heart-pulse me-2"></i>Health
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link text-dark" id="goals-tab" data-bs-toggle="tab" data-bs-target="#goals" type="button" role="tab">
<i class="bi bi-bullseye me-2"></i>Goals
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link text-dark" id="achievements-tab" data-bs-toggle="tab" data-bs-target="#achievements" type="button" role="tab">
<i class="bi bi-trophy me-2"></i>Achievements
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link text-dark" id="tournaments-tab" data-bs-toggle="tab" data-bs-target="#tournaments" type="button" role="tab">
<i class="bi bi-award me-2"></i>Tournaments
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link text-dark" id="events-tab" data-bs-toggle="tab" data-bs-target="#events" type="button" role="tab">
<i class="bi bi-calendar-event me-2"></i>Events
</button>
</li>
</ul>
<!-- Tab Content -->
<div class="tab-content" id="profileTabsContent">
<!-- Overview Tab -->
<div class="tab-pane fade show active" id="overview" role="tabpanel">
<!-- Profile Statistics and Revenue Chart Row -->
<div class="row mb-4">
<!-- Profile Statistics -->
<div class="col-lg-6">
<div class="card shadow-sm border-0 h-100">
<div class="card-body p-4">
<div class="d-flex align-items-center mb-2">
<i class="bi bi-bar-chart-line text-primary me-2"></i>
<h5 class="mb-0 fw-bold">Profile Statistics</h5>
</div>
<p class="text-muted small mb-4">Key performance metrics and milestones</p>
<div class="row g-3">
<!-- Total Sessions -->
<div class="col-md-6">
<div class="d-flex align-items-center gap-3 p-3 bg-light rounded">
<div class="rounded-circle d-flex align-items-center justify-content-center" style="width: 48px; height: 48px; background-color: #6f42c1;">
<i class="bi bi-people-fill text-white"></i>
</div>
<div class="flex-grow-1">
<div class="small text-muted mb-1">Total Sessions</div>
<div class="h4 fw-bold mb-2">127</div>
<div class="progress" style="height: 4px; background-color: #e9ecef;">
<div class="progress-bar" role="progressbar" style="width: 85%; background: linear-gradient(90deg, #6f42c1 0%, #8b5cf6 100%);"></div>
</div>
<small class="text-muted">Sessions completed this year</small>
</div>
</div>
</div>
<!-- Total Revenue -->
<div class="col-md-6">
<div class="d-flex align-items-center gap-3 p-3 bg-light rounded">
<div class="rounded-circle d-flex align-items-center justify-content-center" style="width: 48px; height: 48px; background-color: #10b981;">
<i class="bi bi-currency-dollar text-white"></i>
</div>
<div class="flex-grow-1">
<div class="small text-muted mb-1">Total Revenue</div>
<div class="h4 fw-bold mb-2">$4250</div>
<div class="progress" style="height: 4px; background-color: #e9ecef;">
<div class="progress-bar" role="progressbar" style="width: 70%; background: linear-gradient(90deg, #6f42c1 0%, #10b981 100%);"></div>
</div>
<small class="text-muted">Revenue generated this year</small>
</div>
</div>
</div>
<!-- Attendance Rate -->
<div class="col-md-6">
<div class="d-flex align-items-center gap-3 p-3 bg-light rounded">
<div class="rounded-circle d-flex align-items-center justify-content-center" style="width: 48px; height: 48px; background-color: #3b82f6;">
<i class="bi bi-graph-up-arrow text-white"></i>
</div>
<div class="flex-grow-1">
<div class="small text-muted mb-1">Attendance Rate</div>
<div class="h4 fw-bold mb-2">85%</div>
<div class="progress" style="height: 4px; background-color: #e9ecef;">
<div class="progress-bar" role="progressbar" style="width: 85%; background: linear-gradient(90deg, #6f42c1 0%, #10b981 100%);"></div>
</div>
<small class="text-muted">Average session attendance</small>
</div>
</div>
</div>
<!-- Member Since -->
<div class="col-md-6">
<div class="d-flex align-items-center gap-3 p-3 bg-light rounded">
<div class="rounded-circle d-flex align-items-center justify-content-center" style="width: 48px; height: 48px; background-color: #f59e0b;">
<i class="bi bi-calendar-check text-white"></i>
</div>
<div class="flex-grow-1">
<div class="small text-muted mb-1">Member Since</div>
<div class="h4 fw-bold mb-2">1.5</div>
<div class="progress" style="height: 4px; background-color: #e9ecef;">
<div class="progress-bar" role="progressbar" style="width: 30%; background: linear-gradient(90deg, #6f42c1 0%, #10b981 100%);"></div>
</div>
<small class="text-muted">Years of membership</small>
</div>
</div>
</div>
<!-- Achievements -->
<div class="col-md-6">
<div class="d-flex align-items-center gap-3 p-3 bg-light rounded">
<div class="rounded-circle d-flex align-items-center justify-content-center" style="width: 48px; height: 48px; background-color: #8b5cf6;">
<i class="bi bi-trophy-fill text-white"></i>
</div>
<div class="flex-grow-1">
<div class="small text-muted mb-1">Achievements</div>
<div class="h4 fw-bold mb-2">8</div>
<div class="progress" style="height: 4px; background-color: #e9ecef;">
<div class="progress-bar" role="progressbar" style="width: 40%; background: linear-gradient(90deg, #6f42c1 0%, #10b981 100%);"></div>
</div>
<small class="text-muted">Total badges earned</small>
</div>
</div>
</div>
<!-- Goal Completion -->
<div class="col-md-6">
<div class="d-flex align-items-center gap-3 p-3 bg-light rounded">
<div class="rounded-circle d-flex align-items-center justify-content-center" style="width: 48px; height: 48px; background-color: #10b981;">
<i class="bi bi-check-circle-fill text-white"></i>
</div>
<div class="flex-grow-1">
<div class="small text-muted mb-1">Goal Completion</div>
<div class="h4 fw-bold mb-2">75%</div>
<div class="progress" style="height: 4px; background-color: #e9ecef;">
<div class="progress-bar" role="progressbar" style="width: 75%; background: linear-gradient(90deg, #6f42c1 0%, #10b981 100%);"></div>
</div>
<small class="text-muted">Current goals achieved</small>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Revenue Chart -->
<div class="col-lg-6">
<div class="card shadow-sm border-0 h-100">
<div class="card-body p-4">
<div class="d-flex align-items-center mb-2">
<i class="bi bi-bar-chart-line text-primary me-2"></i>
<h5 class="mb-0 fw-bold">Revenue Chart</h5>
</div>
<p class="text-muted small mb-4">Revenue analytics over time</p>
<div class="d-flex align-items-center justify-content-center" style="min-height: 300px;">
<div class="text-center">
<i class="bi bi-graph-up text-muted" style="font-size: 3rem;"></i>
<p class="text-muted mt-3 mb-1">Revenue chart visualization coming soon...</p>
<small class="text-muted">Chart will display revenue trends over time</small>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Memberships -->
<div class="card shadow-sm mt-4">
<div class="card-header bg-white">
<h5 class="mb-0">Club Memberships</h5>
<!-- Complete Payment & Revenue History -->
<div class="card shadow-sm border-0 mb-4">
<div class="card-body p-4">
<div class="d-flex align-items-center mb-2">
<i class="bi bi-receipt text-primary me-2"></i>
<h5 class="mb-0 fw-bold">Complete Payment & Revenue History</h5>
</div>
<p class="text-muted small mb-4">All package payments and revenue transactions in one view</p>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead class="table-light">
<tr>
<th class="text-muted small fw-semibold">Date</th>
<th class="text-muted small fw-semibold">Transaction Type</th>
<th class="text-muted small fw-semibold">Package/Item</th>
<th class="text-muted small fw-semibold">Duration</th>
<th class="text-muted small fw-semibold">Sessions</th>
<th class="text-muted small fw-semibold">Amount</th>
<th class="text-muted small fw-semibold">Status</th>
<th class="text-muted small fw-semibold">Method</th>
<th class="text-muted small fw-semibold">Evidence</th>
</tr>
</thead>
<tbody>
<tr>
<td class="small">2023-12-15</td>
<td class="small text-primary">Package Payment</td>
<td class="small">Premium Fitness + Personal Training</td>
<td class="small text-muted">2023-12-15 to 2024-06-15</td>
<td class="small">18/24</td>
<td class="small fw-semibold" style="color: #10b981;">649.5 BHD</td>
<td><span class="badge bg-success-subtle text-success small">✓ Paid</span></td>
<td class="small">Credit Card</td>
<td class="small">
<i class="bi bi-file-earmark-text text-primary"></i>
<i class="bi bi-download text-secondary ms-1"></i>
</td>
</tr>
<tr>
<td class="small">2024-02-15</td>
<td class="small text-primary">Package Payment</td>
<td class="small">Premium Fitness + Personal Training</td>
<td class="small text-muted">2023-12-15 to 2024-06-15</td>
<td class="small">18/24</td>
<td class="small fw-semibold" style="color: #f59e0b;">649.5 BHD</td>
<td><span class="badge bg-warning-subtle text-warning small">○ Due</span></td>
<td class="small">Auto-pay</td>
<td class="small">-</td>
</tr>
<tr>
<td class="small">2023-06-15</td>
<td class="small text-primary">Package Payment</td>
<td class="small">Basic Gym Membership</td>
<td class="small text-muted">2023-06-15 to 2023-12-15</td>
<td class="small">Unlimited</td>
<td class="small fw-semibold" style="color: #10b981;">599 BHD</td>
<td><span class="badge bg-success-subtle text-success small">✓ Paid</span></td>
<td class="small">Bank Transfer</td>
<td class="small">
<i class="bi bi-file-earmark-text text-primary"></i>
</td>
</tr>
<tr>
<td class="small">2024-02-01</td>
<td class="small text-primary">Package Payment</td>
<td class="small">Nutrition Consultation Package</td>
<td class="small text-muted">2024-02-01 to 2024-05-01</td>
<td class="small">0/6</td>
<td class="small fw-semibold" style="color: #f59e0b;">450 BHD</td>
<td><span class="badge bg-warning-subtle text-warning small">○ Due</span></td>
<td class="small">Credit Card</td>
<td class="small">-</td>
</tr>
<tr>
<td class="small">2024-01-08</td>
<td class="small text-secondary">Service/Product</td>
<td class="small">Personal Training Session - Paid</td>
<td class="small">-</td>
<td class="small">-</td>
<td class="small fw-semibold" style="color: #10b981;">75 BHD</td>
<td><span class="badge bg-success-subtle text-success small">✓ Paid</span></td>
<td class="small">Credit Card</td>
<td class="small">-</td>
</tr>
<tr>
<td class="small">2024-01-05</td>
<td class="small text-secondary">Service/Product</td>
<td class="small">Protein Supplement - Paid</td>
<td class="small">-</td>
<td class="small">-</td>
<td class="small fw-semibold" style="color: #10b981;">45 BHD</td>
<td><span class="badge bg-success-subtle text-success small">✓ Paid</span></td>
<td class="small">Cash</td>
<td class="small">-</td>
</tr>
<tr>
<td class="small">2024-01-01</td>
<td class="small text-secondary">Service/Product</td>
<td class="small">Monthly Membership - Due</td>
<td class="small">-</td>
<td class="small">-</td>
<td class="small fw-semibold" style="color: #10b981;">99 BHD</td>
<td><span class="badge bg-success-subtle text-success small">✓ Paid</span></td>
<td class="small">Auto-pay</td>
<td class="small">-</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="card-body">
</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="list-group">
<div class="row g-3">
@foreach($relationship->dependent->memberClubs as $club)
<div class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
<div>
<h6 class="mb-1">{{ $club->club_name }}</h6>
<small class="text-muted">Status: {{ ucfirst($club->pivot->status) }}</small>
<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>
<span class="badge bg-{{ $club->pivot->status === 'active' ? 'success' : 'secondary' }} rounded-pill">
{{ ucfirst($club->pivot->status) }}
</span>
</div>
@endforeach
</div>
@@ -96,12 +489,10 @@
</div>
</div>
<!-- Invoices -->
<div class="card shadow-sm mt-4">
<div class="card-header bg-white">
<h5 class="mb-0">Recent Invoices</h5>
</div>
<div class="card-body">
<!-- 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">
@@ -139,19 +530,357 @@
</tbody>
</table>
</div>
@if($relationship->dependent->studentInvoices->count() > 5)
<div class="text-center mt-3">
<a href="{{ route('invoices.index') }}" class="btn btn-outline-primary btn-sm">
View All Invoices
</a>
</div>
@endif
@else
<p class="text-center text-muted my-4">No invoices found.</p>
@endif
</div>
</div>
</div>
<!-- Attendance Tab -->
<div class="tab-pane fade" id="attendance" role="tabpanel">
<div class="card shadow-sm border-0">
<div class="card-body p-4">
<h5 class="fw-bold mb-3">Attendance Records</h5>
<p class="text-muted">Attendance tracking coming soon...</p>
</div>
</div>
</div>
<!-- Health Tab -->
<div class="tab-pane fade" id="health" role="tabpanel">
<!-- Health Tracking Header -->
<div class="card shadow-sm border-0 mb-4">
<div class="card-body p-4">
<div class="d-flex align-items-center mb-2">
<i class="bi bi-heart-pulse text-danger me-2"></i>
<h5 class="mb-0 fw-bold">Health Tracking</h5>
</div>
<p class="text-muted small mb-4">Monitor health metrics and progress over time</p>
<!-- Health Metrics Cards -->
<div class="row g-3">
<!-- Weight -->
<div class="col-md-2">
<div class="text-center p-3 bg-light rounded">
<i class="bi bi-speedometer2 text-purple mb-2" style="font-size: 1.5rem; color: #8b5cf6;"></i>
<div class="h4 fw-bold mb-0">75</div>
<small class="text-muted">Weight (kg)</small>
</div>
</div>
<!-- Body Fat -->
<div class="col-md-2">
<div class="text-center p-3 bg-light rounded">
<i class="bi bi-activity text-warning mb-2" style="font-size: 1.5rem;"></i>
<div class="h4 fw-bold mb-0">12.8%</div>
<small class="text-muted">Body Fat</small>
</div>
</div>
<!-- Body Water -->
<div class="col-md-2">
<div class="text-center p-3 bg-light rounded">
<i class="bi bi-droplet text-info mb-2" style="font-size: 1.5rem;"></i>
<div class="h4 fw-bold mb-0">68.2%</div>
<small class="text-muted">Body Water</small>
</div>
</div>
<!-- Muscle Mass -->
<div class="col-md-2">
<div class="text-center p-3 bg-light rounded">
<i class="bi bi-heart text-success mb-2" style="font-size: 1.5rem;"></i>
<div class="h4 fw-bold mb-0">70.5</div>
<small class="text-muted">Muscle Mass</small>
</div>
</div>
<!-- Bone Mass -->
<div class="col-md-2">
<div class="text-center p-3 bg-light rounded">
<i class="bi bi-capsule text-secondary mb-2" style="font-size: 1.5rem;"></i>
<div class="h4 fw-bold mb-0">3.7</div>
<small class="text-muted">Bone Mass</small>
</div>
</div>
<!-- BMR -->
<div class="col-md-2">
<div class="text-center p-3 bg-light rounded">
<i class="bi bi-lightning text-danger mb-2" style="font-size: 1.5rem;"></i>
<div class="h4 fw-bold mb-0">1895</div>
<small class="text-muted">BMR (cal)</small>
</div>
</div>
</div>
</div>
</div>
<!-- Body Composition Analysis & Compare Row -->
<div class="row mb-4">
<!-- Body Composition Analysis -->
<div class="col-lg-7">
<div class="card shadow-sm border-0 h-100">
<div class="card-body p-4">
<h5 class="fw-bold mb-4">Body Composition Analysis</h5>
<div class="text-center py-5">
<i class="bi bi-radar text-muted" style="font-size: 3rem;"></i>
<p class="text-muted mt-3 mb-1">Radar chart visualization coming soon...</p>
<small class="text-muted">Chart will compare current vs previous body composition metrics</small>
</div>
</div>
</div>
</div>
<!-- Compare -->
<div class="col-lg-5">
<div class="card shadow-sm border-0 h-100">
<div class="card-body p-4">
<h5 class="fw-bold mb-4">Compare</h5>
<div class="table-responsive">
<table class="table table-sm align-middle">
<thead>
<tr class="border-bottom">
<th class="text-muted small fw-semibold">Metric</th>
<th class="text-muted small fw-semibold text-end">Current</th>
<th class="text-muted small fw-semibold text-center">Change</th>
<th class="text-muted small fw-semibold text-end">Previous</th>
</tr>
</thead>
<tbody>
<tr>
<td class="small"><i class="bi bi-speedometer2 me-2"></i>Weight</td>
<td class="small text-end fw-semibold">75kg</td>
<td class="text-center"><i class="bi bi-arrow-down text-success"></i></td>
<td class="small text-end text-muted">77kg</td>
</tr>
<tr>
<td class="small"><i class="bi bi-activity me-2"></i>Body Fat</td>
<td class="small text-end fw-semibold">12.8%</td>
<td class="text-center"><i class="bi bi-arrow-down text-success"></i></td>
<td class="small text-end text-muted">14.5%</td>
</tr>
<tr>
<td class="small"><i class="bi bi-calculator me-2"></i>BMI</td>
<td class="small text-end fw-semibold">22.5</td>
<td class="text-center"><i class="bi bi-arrow-down text-success"></i></td>
<td class="small text-end text-muted">23.2</td>
</tr>
<tr>
<td class="small"><i class="bi bi-droplet me-2"></i>Body Water</td>
<td class="small text-end fw-semibold">68.2%</td>
<td class="text-center"><i class="bi bi-arrow-up text-success"></i></td>
<td class="small text-end text-muted">65.8%</td>
</tr>
<tr>
<td class="small"><i class="bi bi-heart me-2"></i>Muscle Mass</td>
<td class="small text-end fw-semibold">70.5kg</td>
<td class="text-center"><i class="bi bi-arrow-up text-success"></i></td>
<td class="small text-end text-muted">68.2kg</td>
</tr>
<tr>
<td class="small"><i class="bi bi-capsule me-2"></i>Bone Mass</td>
<td class="small text-end fw-semibold">3.7kg</td>
<td class="text-center"><i class="bi bi-arrow-up text-success"></i></td>
<td class="small text-end text-muted">3.6kg</td>
</tr>
<tr>
<td class="small"><i class="bi bi-activity me-2"></i>Visceral Fat</td>
<td class="small text-end fw-semibold">3</td>
<td class="text-center"><i class="bi bi-arrow-down text-success"></i></td>
<td class="small text-end text-muted">4</td>
</tr>
<tr>
<td class="small"><i class="bi bi-lightning me-2"></i>BMR</td>
<td class="small text-end fw-semibold">1895cal</td>
<td class="text-center"><i class="bi bi-arrow-up text-success"></i></td>
<td class="small text-end text-muted">1865cal</td>
</tr>
<tr>
<td class="small"><i class="bi bi-heart-pulse me-2"></i>Protein</td>
<td class="small text-end fw-semibold">19.8%</td>
<td class="text-center"><i class="bi bi-arrow-up text-success"></i></td>
<td class="small text-end text-muted">18.9%</td>
</tr>
<tr>
<td class="small"><i class="bi bi-calendar-heart me-2"></i>Body Age</td>
<td class="small text-end fw-semibold">25yrs</td>
<td class="text-center"><i class="bi bi-arrow-down text-success"></i></td>
<td class="small text-end text-muted">27yrs</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- Health Tracking History -->
<div class="card shadow-sm border-0">
<div class="card-body p-4">
<h5 class="fw-bold mb-4">Health Tracking History</h5>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead class="table-light">
<tr>
<th class="text-muted small fw-semibold">Date</th>
<th class="text-muted small fw-semibold text-center"><i class="bi bi-speedometer2 me-1"></i>Weight (kg)</th>
<th class="text-muted small fw-semibold text-center"><i class="bi bi-activity me-1"></i>Body Fat %</th>
<th class="text-muted small fw-semibold text-center"><i class="bi bi-calculator me-1"></i>BMI</th>
<th class="text-muted small fw-semibold text-center"><i class="bi bi-droplet me-1"></i>Body Water %</th>
<th class="text-muted small fw-semibold text-center"><i class="bi bi-heart me-1"></i>Muscle Mass (kg)</th>
<th class="text-muted small fw-semibold text-center"><i class="bi bi-capsule me-1"></i>Bone Mass (kg)</th>
<th class="text-muted small fw-semibold text-center"><i class="bi bi-activity me-1"></i>Visceral Fat</th>
<th class="text-muted small fw-semibold text-center"><i class="bi bi-lightning me-1"></i>BMR</th>
<th class="text-muted small fw-semibold text-center"><i class="bi bi-heart-pulse me-1"></i>Protein %</th>
<th class="text-muted small fw-semibold text-center"><i class="bi bi-calendar-heart me-1"></i>Body Age</th>
</tr>
</thead>
<tbody>
<tr>
<td class="small fw-semibold">Jan 08, 2024</td>
<td class="small text-center">75</td>
<td class="small text-center">12.8</td>
<td class="small text-center">22.5</td>
<td class="small text-center">68.2</td>
<td class="small text-center">70.5</td>
<td class="small text-center">3.7</td>
<td class="small text-center">3</td>
<td class="small text-center">1895</td>
<td class="small text-center">19.8</td>
<td class="small text-center">25</td>
</tr>
<tr>
<td class="small fw-semibold">Jan 01, 2024</td>
<td class="small text-center">77</td>
<td class="small text-center">14.5</td>
<td class="small text-center">23.2</td>
<td class="small text-center">65.8</td>
<td class="small text-center">68.2</td>
<td class="small text-center">3.6</td>
<td class="small text-center">4</td>
<td class="small text-center">1865</td>
<td class="small text-center">18.9</td>
<td class="small text-center">27</td>
</tr>
<tr>
<td class="small fw-semibold">Dec 25, 2023</td>
<td class="small text-center">79</td>
<td class="small text-center">16.8</td>
<td class="small text-center">23.9</td>
<td class="small text-center">63.2</td>
<td class="small text-center">66.7</td>
<td class="small text-center">3.5</td>
<td class="small text-center">5</td>
<td class="small text-center">1845</td>
<td class="small text-center">18.2</td>
<td class="small text-center">29</td>
</tr>
<tr>
<td class="small fw-semibold">Dec 18, 2023</td>
<td class="small text-center">82</td>
<td class="small text-center">19.2</td>
<td class="small text-center">24.6</td>
<td class="small text-center">60.8</td>
<td class="small text-center">64.7</td>
<td class="small text-center">3.4</td>
<td class="small text-center">7</td>
<td class="small text-center">1820</td>
<td class="small text-center">17.6</td>
<td class="small text-center">31</td>
</tr>
<tr>
<td class="small fw-semibold">Dec 11, 2023</td>
<td class="small text-center">84</td>
<td class="small text-center">21.5</td>
<td class="small text-center">25.2</td>
<td class="small text-center">58.5</td>
<td class="small text-center">63</td>
<td class="small text-center">3.4</td>
<td class="small text-center">8</td>
<td class="small text-center">1795</td>
<td class="small text-center">17.1</td>
<td class="small text-center">33</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Goals Tab -->
<div class="tab-pane fade" id="goals" role="tabpanel">
<div class="card shadow-sm border-0">
<div class="card-body p-4">
<h5 class="fw-bold mb-3">Goals & Progress</h5>
<p class="text-muted">Goal tracking coming soon...</p>
</div>
</div>
</div>
<!-- Achievements Tab -->
<div class="tab-pane fade" id="achievements" role="tabpanel">
<div class="card shadow-sm border-0">
<div class="card-body p-4">
<h5 class="fw-bold mb-3">Achievements & Badges</h5>
<p class="text-muted">Achievement system coming soon...</p>
</div>
</div>
</div>
<!-- Tournaments Tab -->
<div class="tab-pane fade" id="tournaments" role="tabpanel">
<div class="card shadow-sm border-0">
<div class="card-body p-4">
<h5 class="fw-bold mb-3">Tournament History</h5>
<p class="text-muted">Tournament records coming soon...</p>
</div>
</div>
</div>
<!-- Events Tab -->
<div class="tab-pane fade" id="events" role="tabpanel">
<div class="card shadow-sm border-0">
<div class="card-body p-4">
<h5 class="fw-bold mb-3">Event Participation</h5>
<p class="text-muted">Event history coming soon...</p>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Load countries from JSON file
fetch('/data/countries.json')
.then(response => response.json())
.then(countries => {
// Convert all nationality displays from ISO3 to country name with flag
document.querySelectorAll('.nationality-display').forEach(element => {
const iso3Code = element.getAttribute('data-iso3');
if (!iso3Code) return;
const country = countries.find(c => c.iso3 === iso3Code);
if (country) {
// Get flag emoji from ISO2 code
const flagEmoji = country.iso2
.toUpperCase()
.split('')
.map(char => String.fromCodePoint(127397 + char.charCodeAt(0)))
.join('');
element.textContent = `${flagEmoji} ${country.name}`;
}
});
})
.catch(error => console.error('Error loading countries:', error));
});
</script>
@endsection
+20 -4
View File
@@ -18,6 +18,12 @@
<!-- Bootstrap Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css">
<!-- Flag Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/css/flag-icons.min.css">
<!-- Select2 CSS -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/select2.min.css" rel="stylesheet" />
<!-- Custom Styles -->
<style>
body {
@@ -52,12 +58,14 @@
border-color: #0a58ca;
}
</style>
@stack('styles')
</head>
<body>
<nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="{{ url('/') }}">
{{ config('app.name', 'Club SaaS') }}
<img src="{{ asset('images/logo.png') }}" alt="TAKEONE" height="40">
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
<span class="navbar-toggler-icon"></span>
@@ -67,6 +75,9 @@
<!-- Left Side Of Navbar -->
<ul class="navbar-nav me-auto">
@auth
<li class="nav-item">
<a class="nav-link" href="#">Marketplace</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ route('family.dashboard') }}">My Family</a>
</li>
@@ -98,9 +109,6 @@
</a>
<div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="{{ route('profile.edit') }}">
{{ __('Profile') }}
</a>
<a class="dropdown-item" href="{{ route('logout') }}"
onclick="event.preventDefault();
document.getElementById('logout-form').submit();">
@@ -124,5 +132,13 @@
<!-- Bootstrap JS Bundle with Popper -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<!-- jQuery (required for Select2) -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- Select2 JS -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/select2.min.js"></script>
@stack('scripts')
</body>
</html>