takeone/resources/views/components/edit-profile-modal.blade.php

1006 lines
50 KiB
PHP

@props([
'user',
'formAction',
'formMethod' => 'PUT',
'cancelUrl' => null,
'showRelationshipFields' => false,
'relationship' => null,
])
<!-- Profile Edit Modal -->
<div class="modal fade" id="editProfileModal" tabindex="-1" aria-labelledby="editProfileModalLabel" aria-hidden="true" data-bs-backdrop="static" data-bs-keyboard="false">
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable" style="max-width: 75%; width: 1000px;">
<div class="modal-content">
<div class="modal-header bg-primary text-white">
<h5 class="modal-title" id="editProfileModalLabel">
<i class="bi bi-person-circle me-2"></i>Edit Profile
</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body p-0">
<!-- Tab Navigation -->
<ul class="nav nav-tabs nav-fill border-bottom" id="profileEditTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="photo-tab" data-bs-toggle="tab" data-bs-target="#photo" type="button" role="tab" aria-controls="photo" aria-selected="true">
<i class="bi bi-camera me-1"></i>Profile Photo
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="personal-tab" data-bs-toggle="tab" data-bs-target="#personal" type="button" role="tab" aria-controls="personal" aria-selected="false">
<i class="bi bi-person-badge me-1"></i>Personal Info
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="social-tab" data-bs-toggle="tab" data-bs-target="#social" type="button" role="tab" aria-controls="social" aria-selected="false">
<i class="bi bi-share me-1"></i>Social Media
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="additional-tab" data-bs-toggle="tab" data-bs-target="#additional" type="button" role="tab" aria-controls="additional" aria-selected="false">
<i class="bi bi-info-circle me-1"></i>Additional Info
</button>
</li>
</ul>
<form method="POST" action="{{ $formAction }}" id="profileEditForm">
@csrf
@method($formMethod)
<!-- Tab Content -->
<div class="tab-content p-4" id="profileEditTabContent" style="height: 500px; overflow-y: auto;">
<!-- Profile Photo Tab -->
<div class="tab-pane fade show active" id="photo" role="tabpanel" aria-labelledby="photo-tab">
@php
$currentProfileImage = '';
if ($user->profile_picture && file_exists(public_path('storage/' . $user->profile_picture))) {
$currentProfileImage = asset('storage/' . $user->profile_picture);
} else {
$extensions = ['png', 'jpg', 'jpeg', 'webp'];
foreach ($extensions as $ext) {
$path = 'storage/images/profiles/profile_' . $user->id . '.' . $ext;
if (file_exists(public_path($path))) {
$currentProfileImage = asset($path);
break;
}
}
}
@endphp
<div class="row g-4">
<!-- Left Side - Profile Picture -->
<div class="col-md-5">
<div class="profile-photo-preview-container text-center">
<div class="image-preview mb-3">
@if($currentProfileImage)
<img src="{{ $currentProfileImage }}"
alt="Profile Picture"
id="profile_picture_preview"
class="image-upload-preview"
style="width: 300px; height: 400px; object-fit: cover; border: 3px solid #dee2e6; border-radius: 8px;">
@else
<div class="image-placeholder"
id="profile_picture_placeholder"
style="width: 300px; height: 400px; background-color: #f0f0f0; border: 3px solid #dee2e6; border-radius: 8px; display: flex; align-items: center; justify-content: center; margin: 0 auto;">
<div class="text-center">
<i class="bi bi-person-circle" style="font-size: 60px; color: #dee2e6;"></i>
<p class="text-muted mt-2 mb-0">No profile picture</p>
</div>
</div>
@endif
</div>
<input type="hidden" name="remove_profile_picture" id="removeProfilePictureInput" value="0">
</div>
</div>
<!-- Right Side - Information & Controls -->
<div class="col-md-7">
<div class="profile-photo-info" style="max-height: 400px; overflow: hidden;">
<!-- Motivational Header -->
<div class="mb-3">
<h6 class="text-primary mb-2">
<i class="bi bi-camera-fill me-2"></i>Your Athletic Identity
</h6>
<div class="alert alert-info border-0 shadow-sm p-2" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white;">
<div class="d-flex align-items-start">
<i class="bi bi-lightbulb-fill fs-5 me-2"></i>
<div>
<p class="mb-1 small"><strong>Make Your Profile Stand Out!</strong></p>
<p class="mb-0" style="font-size: 0.75rem;">Your profile picture is your athletic CV and first impression. Use a clear, professional photo to help coaches and teammates recognize you!</p>
</div>
</div>
</div>
</div>
<!-- Privacy Toggle -->
<div class="privacy-settings-card mb-3">
<div class="card border-0 shadow-sm">
<div class="card-body p-3">
<div class="d-flex justify-content-between align-items-center mb-2">
<div class="flex-grow-1 me-2">
<h6 class="mb-1">
<i class="bi bi-shield-lock-fill text-primary me-1"></i>Privacy Settings
</h6>
<p class="text-muted mb-0 small">Toggle to control visibility</p>
</div>
<div class="form-check form-switch" style="font-size: 1.2rem;">
<input class="form-check-input" type="checkbox" role="switch"
id="profilePictureVisibility"
name="profile_picture_is_public"
value="1"
{{ old('profile_picture_is_public', $user->profile_picture_is_public ?? true) ? 'checked' : '' }}>
</div>
</div>
<div id="visibilityStatus" class="alert mb-0 p-2" role="alert">
<div class="d-flex align-items-start">
<i class="bi me-2 mt-1" id="visibilityIcon" style="font-size: 1.3rem;"></i>
<div style="flex: 1; min-width: 0;">
<strong class="d-block" id="visibilityTitle" style="font-size: 0.9rem;"></strong>
<p class="mb-0 small" id="visibilityDescription"></p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Photo Guidelines & Action Buttons -->
<div class="d-flex gap-3">
<div style="flex: 1; min-width: 0;">
<h6 class="text-muted mb-2 small">
<i class="bi bi-check-circle-fill me-1"></i>Quick Tips
</h6>
<ul class="list-unstyled text-muted mb-0 small">
<li class="mb-1"><i class="bi bi-check text-success me-1"></i>Recent, high-quality</li>
<li class="mb-1"><i class="bi bi-check text-success me-1"></i>Face clearly visible</li>
<li class="mb-1"><i class="bi bi-check text-success me-1"></i>Professional look</li>
<li class="mb-0"><i class="bi bi-check text-success me-1"></i>Good lighting</li>
</ul>
</div>
<div style="min-width: 120px;">
<h6 class="text-muted mb-2 small">
<i class="bi bi-gear-fill me-1"></i>Actions
</h6>
<x-takeone-cropper
id="profile_picture"
width="300"
height="400"
shape="rectangle"
folder="images/profiles"
filename="profile_{{ $user->id }}"
uploadUrl="{{ $attributes->get('uploadUrl') }}"
currentImage="{{ $currentProfileImage }}"
buttonText="Change Photo"
buttonClass="btn btn-success btn-sm w-100"
/>
<button type="button" class="btn btn-outline-danger btn-sm w-100 mt-2" id="removeProfilePicture" @if(!$currentProfileImage) style="display: none;" @endif>
<i class="bi bi-trash me-1"></i>Remove
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Personal Info Tab -->
<div class="tab-pane fade" id="personal" role="tabpanel" aria-labelledby="personal-tab">
<div class="mb-3">
<label for="full_name" class="form-label">Full Name</label>
<input type="text" class="form-control @error('full_name') is-invalid @enderror" id="full_name" name="full_name" value="{{ old('full_name', $user->full_name) }}" required>
@error('full_name')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label for="email" class="form-label">Email Address</label>
<input type="email" class="form-control @error('email') is-invalid @enderror" id="email" name="email" value="{{ old('email', $user->email) }}" {{ $showRelationshipFields ? '' : 'required' }}>
@error('email')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label for="mobile_number" class="form-label">Mobile Number</label>
<x-country-code-dropdown
name="mobile_code"
id="country_code"
:value="old('mobile_code', $user->mobile['code'] ?? '+973')"
:required="false"
:error="$errors->first('mobile_code')">
<input id="mobile_number" type="tel"
class="form-control @error('mobile') is-invalid @enderror"
name="mobile"
value="{{ old('mobile', $user->mobile['number'] ?? '') }}"
autocomplete="tel"
placeholder="Phone number">
</x-country-code-dropdown>
@error('mobile')
<div class="invalid-feedback d-block">{{ $message }}</div>
@enderror
</div>
<div class="row mb-3">
<div class="col-md-3">
<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="m" {{ old('gender', $user->gender) == 'm' ? 'selected' : '' }}>♂️ Male</option>
<option value="f" {{ old('gender', $user->gender) == 'f' ? 'selected' : '' }}>♀️ Female</option>
</select>
@error('gender')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="col-md-3">
<label for="marital_status" class="form-label">Marital Status</label>
<select class="form-select @error('marital_status') is-invalid @enderror" id="marital_status" name="marital_status">
<option value="">Select Status</option>
<option value="single" {{ old('marital_status', $user->marital_status) == 'single' ? 'selected' : '' }}>💍 Single</option>
<option value="married" {{ old('marital_status', $user->marital_status) == 'married' ? 'selected' : '' }}>💑 Married</option>
<option value="divorced" {{ old('marital_status', $user->marital_status) == 'divorced' ? 'selected' : '' }}>📋 Divorced</option>
<option value="widowed" {{ old('marital_status', $user->marital_status) == 'widowed' ? 'selected' : '' }}>🕊️ Widowed</option>
</select>
@error('marital_status')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="col-md-6">
<x-birthdate-dropdown
name="birthdate"
id="birthdate"
label="Birthdate"
:value="old('birthdate', $user->birthdate?->format('Y-m-d'))"
:required="true"
:min-age="10"
:max-age="120"
:error="$errors->first('birthdate')" />
</div>
</div>
<div class="row mb-3">
<div class="col-md-6">
<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', $user->blood_type) == 'A+' ? 'selected' : '' }}>🩸 A+</option>
<option value="A-" {{ old('blood_type', $user->blood_type) == 'A-' ? 'selected' : '' }}>🩸 A-</option>
<option value="B+" {{ old('blood_type', $user->blood_type) == 'B+' ? 'selected' : '' }}>🩸 B+</option>
<option value="B-" {{ old('blood_type', $user->blood_type) == 'B-' ? 'selected' : '' }}>🩸 B-</option>
<option value="AB+" {{ old('blood_type', $user->blood_type) == 'AB+' ? 'selected' : '' }}>🩸 AB+</option>
<option value="AB-" {{ old('blood_type', $user->blood_type) == 'AB-' ? 'selected' : '' }}>🩸 AB-</option>
<option value="O+" {{ old('blood_type', $user->blood_type) == 'O+' ? 'selected' : '' }}>🩸 O+</option>
<option value="O-" {{ old('blood_type', $user->blood_type) == 'O-' ? 'selected' : '' }}>🩸 O-</option>
<option value="Unknown" {{ old('blood_type', $user->blood_type) == 'Unknown' ? 'selected' : '' }}> Unknown</option>
</select>
@error('blood_type')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="col-md-6">
<x-nationality-dropdown
name="nationality"
id="nationality"
:value="old('nationality', $user->nationality)"
:required="true"
:error="$errors->first('nationality')" />
</div>
</div>
@if($showRelationshipFields && $relationship)
<div class="row mb-3">
<div class="col-md-6">
<label for="relationship_type" class="form-label">Relationship</label>
<select class="form-select @error('relationship_type') is-invalid @enderror" id="relationship_type" name="relationship_type">
<option value="">Select Relationship</option>
<option value="son" {{ old('relationship_type', $relationship->relationship_type ?? '') == 'son' ? 'selected' : '' }}>Son</option>
<option value="daughter" {{ old('relationship_type', $relationship->relationship_type ?? '') == 'daughter' ? 'selected' : '' }}>Daughter</option>
<option value="spouse" {{ old('relationship_type', $relationship->relationship_type ?? '') == 'spouse' ? 'selected' : '' }}>Wife</option>
<option value="sponsor" {{ old('relationship_type', $relationship->relationship_type ?? '') == 'sponsor' ? 'selected' : '' }}>Sponsor</option>
<option value="other" {{ old('relationship_type', $relationship->relationship_type ?? '') == 'other' ? 'selected' : '' }}>Other</option>
</select>
@error('relationship_type')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
</div>
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="is_billing_contact" name="is_billing_contact" value="1" {{ old('is_billing_contact', $relationship->is_billing_contact ?? false) ? 'checked' : '' }}>
<label class="form-check-label" for="is_billing_contact">Is Billing Contact</label>
</div>
@endif
</div>
<!-- Social Media Tab -->
<div class="tab-pane fade" id="social" role="tabpanel" aria-labelledby="social-tab">
<div class="mb-3">
<h5 class="form-label d-flex justify-content-between align-items-center">
Social Media Links
<button type="button" class="btn btn-outline-primary btn-sm" id="addSocialLink">
<i class="bi bi-plus"></i> Add Link
</button>
</h5>
<div id="socialLinksContainer">
@php
$existingLinks = old('social_links', $user->social_links ?? []);
if (!is_array($existingLinks)) {
$existingLinks = [];
}
$formLinks = [];
foreach ($existingLinks as $platform => $url) {
$formLinks[] = ['platform' => $platform, 'url' => $url];
}
@endphp
@foreach($formLinks as $index => $link)
@include('components.social-link-row', ['index' => $index, 'link' => $link])
@endforeach
</div>
</div>
</div>
<!-- Additional Info Tab -->
<div class="tab-pane fade" id="additional" role="tabpanel" aria-labelledby="additional-tab">
<div class="mb-3">
<label for="motto" class="form-label">Personal Motto</label>
<textarea class="form-control @error('motto') is-invalid @enderror" id="motto" name="motto" rows="4" placeholder="Enter personal motto or quote...">{{ old('motto', $user->motto) }}</textarea>
<div class="form-text">Share a personal motto or quote that inspires you.</div>
@error('motto')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer bg-light">
<div class="d-flex justify-content-between align-items-center w-100">
<div>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
</div>
<div>
<button type="submit" class="btn btn-success" id="submitBtn" form="profileEditForm">
<i class="bi bi-check-circle me-1"></i>Update Profile
</button>
</div>
<div>
<button type="button" class="btn btn-outline-secondary me-2" id="prevBtn" style="display: none;">
<i class="bi bi-arrow-left me-1"></i>Previous
</button>
<button type="button" class="btn btn-primary" id="nextBtn">
Next<i class="bi bi-arrow-right ms-1"></i>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
@push('styles')
<style>
/* Profile Photo Tab Styles */
.profile-photo-preview-container {
position: relative;
transition: transform 0.3s ease;
}
.profile-photo-preview-container:hover {
transform: translateY(-5px);
}
.profile-photo-info {
animation: fadeInRight 0.5s ease-out;
}
@keyframes fadeInRight {
from {
opacity: 0;
transform: translateX(20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
.privacy-settings-card {
transition: all 0.3s ease;
}
.privacy-settings-card:hover {
transform: translateY(-2px);
}
.privacy-settings-card .card {
transition: box-shadow 0.3s ease;
}
.privacy-settings-card .card:hover {
box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.15) !important;
}
.form-check-input:checked {
background-color: #28a745;
border-color: #28a745;
}
.form-check-input:focus {
border-color: #86b7fe;
outline: 0;
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
}
/* Animated gradient background for motivational section */
.alert-info {
animation: gradientShift 3s ease infinite;
background-size: 200% 200%;
}
@keyframes gradientShift {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
/* Guidelines list - no animation to save space */
.profile-photo-info ul li {
transition: color 0.2s ease;
}
.profile-photo-info ul li:hover {
color: #495057;
}
/* Button hover effects */
#removeProfilePicture {
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
#removeProfilePicture::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
border-radius: 50%;
background: rgba(255, 255, 255, 0.3);
transform: translate(-50%, -50%);
transition: width 0.6s, height 0.6s;
}
#removeProfilePicture:hover::before {
width: 300px;
height: 300px;
}
#removeProfilePicture:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(220, 53, 69, 0.3);
}
/* Custom select wrapper */
.custom-select-wrapper {
position: relative;
}
.custom-select-btn {
width: 100%;
text-align: left;
background: white;
border: 1px solid #dee2e6;
padding: 0.375rem 2.25rem 0.375rem 0.75rem;
border-radius: 0.375rem;
cursor: pointer;
position: relative;
}
.custom-select-btn::after {
content: "";
position: absolute;
right: 0.75rem;
top: 50%;
transform: translateY(-50%);
width: 0;
height: 0;
border-left: 0.3em solid transparent;
border-right: 0.3em solid transparent;
border-top: 0.3em solid;
}
.custom-select-btn:hover {
border-color: #86b7fe;
}
.custom-select-dropdown {
position: absolute;
top: 100%;
left: 0;
right: 0;
background: white;
border: 1px solid #dee2e6;
border-radius: 0.375rem;
max-height: 300px;
overflow-y: auto;
z-index: 1000;
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
margin-top: 0.125rem;
}
.custom-select-option {
padding: 0.5rem 0.75rem;
cursor: pointer;
transition: background-color 0.15s ease-in-out;
}
.custom-select-option:hover {
background-color: #f8f9fa;
}
.custom-select-option i {
width: 20px;
display: inline-block;
}
</style>
@endpush
@push('scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
let socialLinkIndex = {{ count($formLinks ?? []) }};
// Tab navigation
const tabs = ['photo', 'personal', 'social', 'additional'];
let currentTab = 0;
const prevBtn = document.getElementById('prevBtn');
const nextBtn = document.getElementById('nextBtn');
const submitBtn = document.getElementById('submitBtn');
function updateButtons() {
prevBtn.style.display = currentTab === 0 ? 'none' : 'inline-block';
nextBtn.style.display = currentTab === tabs.length - 1 ? 'none' : 'inline-block';
}
function showTab(index) {
const tabButton = document.getElementById(tabs[index] + '-tab');
const tab = new bootstrap.Tab(tabButton);
tab.show();
currentTab = index;
updateButtons();
}
nextBtn.addEventListener('click', function() {
if (currentTab < tabs.length - 1) {
showTab(currentTab + 1);
}
});
prevBtn.addEventListener('click', function() {
if (currentTab > 0) {
showTab(currentTab - 1);
}
});
document.querySelectorAll('#profileEditTabs button[data-bs-toggle="tab"]').forEach((tabButton, index) => {
tabButton.addEventListener('shown.bs.tab', function() {
currentTab = index;
updateButtons();
});
});
updateButtons();
// Auto-open modal on page load (only if cancelUrl is set, meaning it's a dedicated edit page)
const editModalEl = document.getElementById('editProfileModal');
const editModal = new bootstrap.Modal(editModalEl);
@if($cancelUrl)
editModal.show();
@endif
// Prevent edit modal from closing when cropper modal opens
let cropperModalOpen = false;
let isSubmitting = false;
document.addEventListener('show.bs.modal', function(event) {
if (event.target.id !== 'editProfileModal') {
cropperModalOpen = true;
}
});
document.addEventListener('hidden.bs.modal', function(event) {
if (event.target.id !== 'editProfileModal') {
cropperModalOpen = false;
// Re-show edit modal after cropper closes, unless we're submitting
if (!editModalEl.classList.contains('show') && !isSubmitting) {
editModal.show();
}
}
});
editModalEl.addEventListener('hide.bs.modal', function(e) {
if (cropperModalOpen && !isSubmitting) {
e.preventDefault();
e.stopPropagation();
return false;
}
});
editModalEl.addEventListener('hidden.bs.modal', function() {
if (!cropperModalOpen && !isSubmitting) {
@if($cancelUrl)
window.location.href = "{{ $cancelUrl }}";
@endif
}
});
@if($errors->any())
editModal.show();
@endif
// Handle form submission with AJAX
const profileForm = document.getElementById('profileEditForm');
submitBtn.addEventListener('click', function(e) {
e.preventDefault();
// Disable submit button to prevent double submission
submitBtn.disabled = true;
submitBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span>Updating...';
const formData = new FormData(profileForm);
fetch(profileForm.action, {
method: 'POST',
body: formData,
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'application/json'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Update profile picture on the page if it was changed
if (data.profile_picture_url) {
// Update all profile pictures on the page
document.querySelectorAll('img[alt*="Profile"], img[src*="profile"]').forEach(img => {
if (img.src.includes('profile_') || img.alt.toLowerCase().includes('profile')) {
img.src = data.profile_picture_url + '?v=' + new Date().getTime();
}
});
}
// Show success message
const alertDiv = document.createElement('div');
alertDiv.className = 'alert alert-success alert-dismissible fade show position-fixed top-0 start-50 translate-middle-x mt-3';
alertDiv.style.zIndex = '9999';
alertDiv.innerHTML = `
<i class="bi bi-check-circle me-2"></i>${data.message || 'Profile updated successfully!'}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
`;
document.body.appendChild(alertDiv);
// Close modal and reload page after short delay
isSubmitting = true;
setTimeout(() => {
editModal.hide();
window.location.reload();
}, 1500);
} else {
throw new Error(data.message || 'Update failed');
}
})
.catch(error => {
console.error('Error:', error);
const alertDiv = document.createElement('div');
alertDiv.className = 'alert alert-danger alert-dismissible fade show position-fixed top-0 start-50 translate-middle-x mt-3';
alertDiv.style.zIndex = '9999';
alertDiv.innerHTML = `
<i class="bi bi-exclamation-triangle me-2"></i>${error.message || 'Failed to update profile. Please try again.'}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
`;
document.body.appendChild(alertDiv);
// Re-enable submit button
submitBtn.disabled = false;
submitBtn.innerHTML = '<i class="bi bi-check-circle me-1"></i>Update Profile';
});
});
// Add new social link row
document.getElementById('addSocialLink').addEventListener('click', function() {
addSocialLinkRow();
});
// Remove social link row
document.addEventListener('click', function(e) {
if (e.target.classList.contains('remove-social-link') || e.target.closest('.remove-social-link')) {
e.target.closest('.social-link-row').remove();
}
});
// Custom select dropdown functionality
document.addEventListener('click', function(e) {
if (e.target.classList.contains('custom-select-btn') || e.target.closest('.custom-select-btn')) {
const btn = e.target.classList.contains('custom-select-btn') ? e.target : e.target.closest('.custom-select-btn');
const dropdown = btn.nextElementSibling.nextElementSibling;
document.querySelectorAll('.custom-select-dropdown').forEach(d => {
if (d !== dropdown) d.style.display = 'none';
});
dropdown.style.display = dropdown.style.display === 'none' ? 'block' : 'none';
e.stopPropagation();
}
else if (e.target.classList.contains('custom-select-option') || e.target.closest('.custom-select-option')) {
const option = e.target.classList.contains('custom-select-option') ? e.target : e.target.closest('.custom-select-option');
const value = option.getAttribute('data-value');
const wrapper = option.closest('.custom-select-wrapper');
const btn = wrapper.querySelector('.custom-select-btn');
const hiddenInput = wrapper.querySelector('.platform-value');
const dropdown = wrapper.querySelector('.custom-select-dropdown');
btn.innerHTML = option.innerHTML;
hiddenInput.value = value;
dropdown.style.display = 'none';
}
else {
document.querySelectorAll('.custom-select-dropdown').forEach(d => {
d.style.display = 'none';
});
}
});
// Listen for image upload success from cropper
document.addEventListener('imageUploaded', function(e) {
if (e.detail && e.detail.url) {
updateProfilePicturePreview(e.detail.url);
}
});
// Also listen for global image upload success callback
window.imageUploadSuccess = function(result) {
console.log('Image upload success callback called:', result);
if (result && result.url) {
console.log('Updating preview with URL:', result.url);
updateProfilePicturePreview(result.url);
// Clear the remove checkbox since we now have a new image
const removeCheckbox = document.getElementById('remove_profile_picture');
if (removeCheckbox) {
removeCheckbox.checked = false;
console.log('Remove checkbox cleared after successful upload');
}
} else if (result && result.path) {
// Some components might return 'path' instead of 'url'
console.log('Updating preview with path:', result.path);
const fullUrl = window.location.origin + '/storage/' + result.path;
console.log('Constructed URL:', fullUrl);
updateProfilePicturePreview(fullUrl);
// Clear the remove checkbox since we now have a new image
const removeCheckbox = document.getElementById('remove_profile_picture');
if (removeCheckbox) {
removeCheckbox.checked = false;
console.log('Remove checkbox cleared after successful upload');
}
} else {
console.log('No URL or path in result:', result);
}
};
function updateProfilePicturePreview(imageUrl) {
console.log('updateProfilePicturePreview called with URL:', imageUrl);
const preview = document.getElementById('profile_picture_preview');
const placeholder = document.getElementById('profile_picture_placeholder');
console.log('Current preview element:', preview);
console.log('Current placeholder element:', placeholder);
if (placeholder) {
console.log('Replacing placeholder with new image');
// Replace placeholder with image
placeholder.style.display = 'none';
const previewContainer = placeholder.parentElement;
const newImg = document.createElement('img');
newImg.src = imageUrl + '?v=' + new Date().getTime();
newImg.alt = 'Profile Picture';
newImg.id = 'profile_picture_preview';
newImg.className = 'image-upload-preview';
newImg.style.cssText = 'width: 300px; height: 400px; object-fit: cover; border: 3px solid #dee2e6; border-radius: 8px;';
previewContainer.appendChild(newImg);
console.log('New image element created and appended');
} else if (preview) {
console.log('Updating existing preview image');
// Update existing image
preview.src = imageUrl + '?v=' + new Date().getTime();
} else {
console.log('No placeholder or preview found!');
}
// Show remove button
const removeBtn = document.getElementById('removeProfilePicture');
if (removeBtn) {
removeBtn.style.display = 'block';
console.log('Remove button shown');
} else {
console.log('Remove button not found');
}
}
// Privacy toggle functionality
const visibilityToggle = document.getElementById('profilePictureVisibility');
const visibilityStatus = document.getElementById('visibilityStatus');
const visibilityIcon = document.getElementById('visibilityIcon');
const visibilityTitle = document.getElementById('visibilityTitle');
const visibilityDescription = document.getElementById('visibilityDescription');
function updateVisibilityStatus() {
const isPublic = visibilityToggle.checked;
if (isPublic) {
visibilityStatus.className = 'alert alert-success mb-0 p-2';
visibilityIcon.className = 'bi bi-globe me-2 mt-1';
visibilityTitle.textContent = 'Public';
visibilityDescription.textContent = 'Everyone can see your profile picture';
} else {
visibilityStatus.className = 'alert alert-warning mb-0 p-2';
visibilityIcon.className = 'bi bi-lock-fill me-2 mt-1';
visibilityTitle.textContent = 'Private';
visibilityDescription.textContent = 'Only you and your family can see your profile picture';
}
}
if (visibilityToggle) {
// Initialize on page load
updateVisibilityStatus();
// Update on toggle change
visibilityToggle.addEventListener('change', function() {
updateVisibilityStatus();
// Add a subtle animation
visibilityStatus.style.opacity = '0';
setTimeout(() => {
visibilityStatus.style.transition = 'opacity 0.3s ease-in-out';
visibilityStatus.style.opacity = '1';
}, 100);
});
}
// Remove profile picture functionality
function attachRemovePhotoListener() {
const removeProfilePictureBtn = document.getElementById('removeProfilePicture');
if (removeProfilePictureBtn && !removeProfilePictureBtn.hasAttribute('data-listener-attached')) {
removeProfilePictureBtn.setAttribute('data-listener-attached', 'true');
removeProfilePictureBtn.addEventListener('click', function() {
// Set the hidden input to indicate removal
document.getElementById('removeProfilePictureInput').value = '1';
// Get user gender for default avatar
const gender = document.getElementById('gender').value || 'm';
// Update preview to show default avatar
const preview = document.getElementById('profile_picture_preview');
const placeholder = document.getElementById('profile_picture_placeholder');
if (preview) {
preview.style.display = 'none';
}
if (placeholder) {
placeholder.style.display = 'flex';
// Update icon based on gender
const icon = placeholder.querySelector('i');
if (icon) {
icon.className = gender === 'f' ? 'bi bi-person-circle' : 'bi bi-person-circle';
icon.style.color = gender === 'f' ? '#e91e63' : '#2196f3';
}
const text = placeholder.querySelector('p');
if (text) {
text.textContent = 'Default avatar will be used';
}
} else {
// Create placeholder if it doesn't exist
const previewContainer = preview ? preview.parentElement : document.querySelector('.image-preview');
if (previewContainer) {
const newPlaceholder = document.createElement('div');
newPlaceholder.className = 'image-placeholder';
newPlaceholder.id = 'profile_picture_placeholder';
newPlaceholder.style.cssText = 'width: 300px; height: 400px; background-color: #f0f0f0; border: 3px solid #dee2e6; border-radius: 8px; display: flex; align-items: center; justify-content: center; margin: 0 auto;';
newPlaceholder.innerHTML = `
<div class="text-center">
<i class="bi bi-person-circle" style="font-size: 60px; color: ${gender === 'f' ? '#e91e63' : '#2196f3'};"></i>
<p class="text-muted mt-2 mb-0">Default avatar will be used</p>
</div>
`;
if (preview) {
preview.parentElement.appendChild(newPlaceholder);
} else {
previewContainer.appendChild(newPlaceholder);
}
}
}
// Hide the remove button
removeProfilePictureBtn.style.display = 'none';
// No notification needed - just remove the picture directly
});
}
}
// Attach listener on page load
attachRemovePhotoListener();
function addSocialLinkRow(platform = '', url = '') {
const container = document.getElementById('socialLinksContainer');
const row = document.createElement('div');
row.className = 'social-link-row mb-3 d-flex align-items-end';
const platformIcons = {
'facebook': '<i class="bi bi-facebook me-2"></i>Facebook',
'twitter': '<i class="bi bi-twitter-x me-2"></i>Twitter/X',
'instagram': '<i class="bi bi-instagram me-2"></i>Instagram',
'linkedin': '<i class="bi bi-linkedin me-2"></i>LinkedIn',
'youtube': '<i class="bi bi-youtube me-2"></i>YouTube',
'tiktok': '<i class="bi bi-tiktok me-2"></i>TikTok',
'snapchat': '<i class="bi bi-snapchat me-2"></i>Snapchat',
'whatsapp': '<i class="bi bi-whatsapp me-2"></i>WhatsApp',
'telegram': '<i class="bi bi-telegram me-2"></i>Telegram',
'discord': '<i class="bi bi-discord me-2"></i>Discord',
'reddit': '<i class="bi bi-reddit me-2"></i>Reddit',
'pinterest': '<i class="bi bi-pinterest me-2"></i>Pinterest',
'twitch': '<i class="bi bi-twitch me-2"></i>Twitch',
'github': '<i class="bi bi-github me-2"></i>GitHub',
'spotify': '<i class="bi bi-spotify me-2"></i>Spotify',
'skype': '<i class="bi bi-skype me-2"></i>Skype',
'slack': '<i class="bi bi-slack me-2"></i>Slack',
'medium': '<i class="bi bi-medium me-2"></i>Medium',
'vimeo': '<i class="bi bi-vimeo me-2"></i>Vimeo',
'messenger': '<i class="bi bi-messenger me-2"></i>Messenger',
'wechat': '<i class="bi bi-wechat me-2"></i>WeChat',
'line': '<i class="bi bi-line me-2"></i>Line'
};
const selectedPlatform = platform ? platformIcons[platform] : 'Select Platform';
row.innerHTML = `
<div class="me-2 flex-grow-1">
<label class="form-label">Platform</label>
<div class="custom-select-wrapper">
<button type="button" class="form-select text-start custom-select-btn" data-index="${socialLinkIndex}">
${selectedPlatform}
</button>
<input type="hidden" name="social_links[${socialLinkIndex}][platform]" value="${platform}" class="platform-value" required>
<div class="custom-select-dropdown" style="display: none;">
${Object.entries(platformIcons).map(([key, value]) =>
`<div class="custom-select-option" data-value="${key}">${value}</div>`
).join('')}
</div>
</div>
</div>
<div class="me-2 flex-grow-1">
<label class="form-label">URL</label>
<input type="url" class="form-control" name="social_links[${socialLinkIndex}][url]" value="${url}" placeholder="https://example.com/username" required>
</div>
<div class="mb-0">
<button type="button" class="btn btn-outline-danger btn-sm remove-social-link">
<i class="bi bi-trash"></i>
</button>
</div>
`;
container.appendChild(row);
socialLinkIndex++;
}
});
</script>
@endpush