built user profile added the logo created the family view etc
This commit is contained in:
1 parent
4a7353e3fc
commit
43c2676d6f
33 files changed
+3783
-257
No files matched your search
@@ -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
|
||||
Reference in new issue
Block a user