academy/resources/views/StudentProfile.blade.php

839 lines
37 KiB
PHP

@extends('layouts.studentportalnav')
@section('title', 'Student Profile')
@section('content')
<!-- Cropper.js CSS & JS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.6.2/cropper.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.6.2/cropper.min.js"></script>
<style>
:root {
--theme-navy: #1E233E;
--theme-navy-dark: #15182C;
--theme-red: #822424;
--theme-red-hover: #df2c3e;
--theme-yellow: #FFEA85;
--theme-bg: #F4F6F9;
--text-dark: #1E293B;
}
/* Page Header Hero */
.profile-hero {
background: linear-gradient(135deg, var(--theme-navy) 0%, #2A1F3B 50%, #4A1A24 100%);
border-radius: 20px;
padding: 32px 38px;
margin-bottom: 28px;
box-shadow: 0 12px 32px rgba(30, 35, 62, 0.16);
position: relative;
overflow: hidden;
}
.profile-hero::before {
content: '';
position: absolute;
top: -50%;
right: -10%;
width: 350px;
height: 350px;
background: radial-gradient(circle, rgba(255, 234, 133, 0.15) 0%, rgba(255, 234, 133, 0) 70%);
border-radius: 50%;
pointer-events: none;
}
/* Profile Summary Card */
.profile-summary-card {
background: #ffffff;
border-radius: 20px;
padding: 36px 28px;
border: 1px solid #E2E8F0;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.03);
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}
.profile-avatar-wrapper {
position: relative;
margin-bottom: 22px;
}
.profile-avatar-box {
width: 140px;
height: 140px;
border-radius: 50%;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.profile-avatar-img {
width: 140px;
height: 140px;
border-radius: 50%;
object-fit: cover;
border: 4px solid var(--theme-navy);
box-shadow: 0 10px 28px rgba(30, 35, 62, 0.18);
background: #ffffff;
}
.profile-avatar-placeholder {
width: 140px;
height: 140px;
border-radius: 50%;
background: linear-gradient(135deg, #1E233E 0%, #15182C 100%);
color: var(--theme-yellow);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border: 4px solid var(--theme-yellow);
box-shadow: 0 10px 28px rgba(30, 35, 62, 0.22);
}
.avatar-initial-letter {
font-size: 52px;
line-height: 1;
font-weight: 800;
color: var(--theme-yellow);
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
}
.student-name-title {
color: var(--theme-navy);
font-weight: 800;
font-size: 1.4rem;
margin-bottom: 12px;
line-height: 1.3;
letter-spacing: -0.3px;
text-transform: capitalize;
}
.student-id-pill {
background: var(--theme-navy);
color: var(--theme-yellow);
padding: 10px 24px;
border-radius: 50px;
font-size: 0.85rem;
font-weight: 700;
letter-spacing: 0.5px;
display: inline-flex;
align-items: center;
gap: 8px;
box-shadow: 0 4px 14px rgba(30, 35, 62, 0.18);
}
.btn-edit-profile {
background: var(--theme-red);
color: #ffffff;
border: none;
border-radius: 12px;
padding: 14px 28px;
font-weight: 700;
font-size: 0.92rem;
box-shadow: 0 6px 18px rgba(130, 36, 36, 0.25);
transition: all 0.25s cubic-bezier(0.16, 1, 0.3, 1);
width: 100%;
}
.btn-edit-profile:hover {
background: var(--theme-red-hover);
color: #ffffff;
transform: translateY(-2px);
box-shadow: 0 10px 24px rgba(130, 36, 36, 0.35);
}
/* Info Cards */
.info-card-modern {
background: #ffffff;
border-radius: 20px;
padding: 30px;
border: 1px solid #E2E8F0;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.03);
height: 100%;
}
.info-card-title {
color: var(--theme-navy);
font-weight: 800;
font-size: 1.15rem;
border-bottom: 2px solid var(--theme-yellow);
padding-bottom: 12px;
margin-bottom: 22px;
display: flex;
align-items: center;
gap: 10px;
}
.info-data-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 14px 0;
border-bottom: 1px solid #F1F5F9;
flex-wrap: wrap;
gap: 8px;
}
.info-data-row:last-child {
border-bottom: none;
}
.info-data-label {
color: #64748B;
font-weight: 600;
font-size: 0.9rem;
display: flex;
align-items: center;
gap: 8px;
}
.info-data-value {
font-weight: 700;
color: #0F172A;
font-size: 0.95rem;
}
/* Course Box Box */
.course-card-dark {
background: linear-gradient(135deg, var(--theme-navy) 0%, var(--theme-navy-dark) 100%);
color: #ffffff;
padding: 30px;
border-radius: 20px;
box-shadow: 0 10px 30px rgba(30, 35, 62, 0.2);
height: 100%;
position: relative;
overflow: hidden;
}
.course-card-dark::before {
content: '';
position: absolute;
top: -40%;
right: -20%;
width: 280px;
height: 280px;
background: radial-gradient(circle, rgba(255, 234, 133, 0.08) 0%, rgba(255, 234, 133, 0) 70%);
border-radius: 50%;
pointer-events: none;
}
.course-card-title {
color: var(--theme-yellow);
font-weight: 800;
font-size: 1.15rem;
margin-bottom: 22px;
border-bottom: 1px solid rgba(255, 255, 255, 0.12);
padding-bottom: 12px;
display: flex;
align-items: center;
gap: 10px;
}
.course-item-row {
margin-bottom: 16px;
font-size: 0.92rem;
color: rgba(255, 255, 255, 0.9);
display: flex;
align-items: center;
gap: 12px;
}
.course-item-row:last-child {
margin-bottom: 0;
}
.course-item-row i {
color: var(--theme-yellow);
width: 24px;
font-size: 1.1rem;
text-align: center;
}
/* Cropper Circular Mask styling */
.cropper-view-box,
.cropper-face {
border-radius: 50%;
}
.btn-emoji-picker {
transition: transform 0.2s ease, background-color 0.2s ease;
}
.btn-emoji-picker:hover {
transform: scale(1.2);
background-color: #E2E8F0 !important;
}
.btn-avatar-color {
cursor: pointer;
transition: transform 0.2s ease;
}
.btn-avatar-color:hover {
transform: scale(1.25);
}
</style>
<div class="portal-content-container">
@if(session('success'))
<div class="alert alert-success alert-dismissible fade show rounded-4 border-0 shadow-sm mb-4" role="alert">
<i class="fa-solid fa-circle-check me-2"></i> {{ session('success') }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
@endif
@if(session('error'))
<div class="alert alert-danger alert-dismissible fade show rounded-4 border-0 shadow-sm mb-4" role="alert">
<i class="fa-solid fa-triangle-exclamation me-2"></i> {{ session('error') }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
@endif
<!-- Hero Header -->
<div class="profile-hero d-flex align-items-center justify-content-between flex-wrap gap-3">
<div class="position-relative" style="z-index: 1;">
<div class="d-flex align-items-center gap-2 mb-2">
<span class="badge bg-warning bg-opacity-20 text-warning border border-warning border-opacity-20 px-3 py-1.5 rounded-pill fw-semibold" style="font-size: 0.78rem;">
<i class="fa-solid fa-user-check me-1"></i> Verified Student Profile
</span>
</div>
<h2 class="fw-bold text-white mb-1" style="letter-spacing: -0.5px;">
<i class="fa-solid fa-user-graduate me-2" style="color: var(--theme-yellow);"></i>Student Profile
</h2>
<p class="text-white-50 mb-0 fs-6">
Manage your personal information, credentials, and academic details.
</p>
</div>
</div>
<!-- Main Profile Row -->
<div class="row g-4 mb-4">
<!-- Profile Summary Card -->
<div class="col-lg-4">
<div class="profile-summary-card">
<div class="profile-avatar-wrapper">
<div class="profile-avatar-box">
@if(!empty($student->image))
<img src="{{ asset($student->image) }}" class="profile-avatar-img" alt="{{ $student->full_name }}" onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';">
@endif
<div class="profile-avatar-placeholder" style="{{ !empty($student->image) ? 'display: none;' : 'display: flex;' }}">
<span class="avatar-initial-letter">{{ strtoupper(substr($student->full_name ?? 'S', 0, 1)) }}</span>
</div>
</div>
</div>
<h3 class="student-name-title">{{ $student->full_name }}</h3>
<div class="mb-4">
<span class="student-id-pill">
<i class="fa-solid fa-id-badge text-warning"></i> Student ID : {{ $student->student_id }}
</span>
</div>
<div class="w-100 pt-3 border-top border-slate-100 mt-auto">
<button class="btn btn-edit-profile" data-bs-toggle="modal" data-bs-target="#editProfileModal">
<i class="fa-solid fa-pen-to-square me-2"></i> Edit Profile
</button>
</div>
</div>
</div>
<!-- Personal Details -->
<div class="col-lg-8">
<div class="info-card-modern">
<h4 class="info-card-title">
<i class="fa-solid fa-id-card text-danger"></i> Personal Information
</h4>
<div class="info-data-row">
<span class="info-data-label"><i class="fa-regular fa-user text-muted"></i> Full Name</span>
<span class="info-data-value text-capitalize">{{ $student->full_name }}</span>
</div>
<div class="info-data-row">
<span class="info-data-label"><i class="fa-regular fa-address-card text-muted"></i> NIC / Passport</span>
<span class="info-data-value">{{ $student->nic_passport }}</span>
</div>
<div class="info-data-row">
<span class="info-data-label"><i class="fa-regular fa-calendar text-muted"></i> Date of Birth</span>
<span class="info-data-value">
{{ !empty($student->date_of_birth) ? date('d F Y', strtotime($student->date_of_birth)) : 'N/A' }}
</span>
</div>
<div class="info-data-row">
<span class="info-data-label"><i class="fa-solid fa-venus-mars text-muted"></i> Gender</span>
<span class="info-data-value text-capitalize">{{ $student->gender }}</span>
</div>
<div class="info-data-row">
<span class="info-data-label"><i class="fa-regular fa-envelope text-muted"></i> Email Address</span>
<span class="info-data-value text-primary">{{ $student->email }}</span>
</div>
<div class="info-data-row">
<span class="info-data-label"><i class="fa-solid fa-phone text-muted"></i> Phone Number</span>
<span class="info-data-value">{{ $student->phone }}</span>
</div>
</div>
</div>
</div>
<!-- Education & Course Details Row -->
<div class="row g-4 mb-5">
<!-- Educational Background -->
<div class="col-lg-6">
<div class="info-card-modern">
<h4 class="info-card-title">
<i class="fa-solid fa-graduation-cap text-danger"></i> Educational Background
</h4>
<div class="info-data-row">
<span class="info-data-label"><i class="fa-solid fa-certificate text-muted"></i> Qualification</span>
<span class="info-data-value">{{ $student->qualification }}</span>
</div>
<div class="info-data-row">
<span class="info-data-label"><i class="fa-solid fa-building-columns text-muted"></i> Institute</span>
<span class="info-data-value">{{ $student->institute }}</span>
</div>
<div class="info-data-row">
<span class="info-data-label"><i class="fa-regular fa-calendar-check text-muted"></i> Year Completed</span>
<span class="info-data-value">{{ $student->year_completed }}</span>
</div>
</div>
</div>
<!-- Course Details -->
<div class="col-lg-6">
<div class="course-card-dark">
<h4 class="course-card-title">
<i class="fa-solid fa-car-side"></i> Course Details
</h4>
<div class="course-item-row">
<i class="fa-solid fa-book"></i>
<div>
<span class="text-white-50 d-block small" style="font-size: 0.75rem;">Enrolled Course</span>
<strong class="text-white fs-6">{{ $student->course_name }}</strong>
</div>
</div>
<div class="course-item-row">
<i class="fa-solid fa-clock"></i>
<div>
<span class="text-white-50 d-block small" style="font-size: 0.75rem;">Duration</span>
<strong class="text-white">{{ $student->duration }}</strong>
</div>
</div>
<div class="course-item-row">
<i class="fa-solid fa-layer-group"></i>
<div>
<span class="text-white-50 d-block small" style="font-size: 0.75rem;">Current Semester</span>
<strong class="text-white">{{ $student->current_semester }}</strong>
</div>
</div>
<div class="course-item-row">
<i class="fa-solid fa-user-tie"></i>
<div>
<span class="text-white-50 d-block small" style="font-size: 0.75rem;">Instructor / Trainer</span>
<strong class="text-white">{{ $student->trainer_name }}</strong>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- EDIT PROFILE MODAL -->
<div class="modal fade" id="editProfileModal" tabindex="-1" aria-labelledby="editProfileModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-lg">
<div class="modal-content border-0 rounded-4 shadow-lg overflow-hidden">
<div class="modal-header text-white p-4" style="background: linear-gradient(135deg, var(--theme-navy) 0%, var(--theme-navy-dark) 100%);">
<h5 class="modal-title fw-bold" id="editProfileModalLabel">
<i class="fa-solid fa-user-gear me-2" style="color: var(--theme-yellow);"></i> Edit Student Profile
</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="{{ route('student.profile.update') }}" method="POST" enctype="multipart/form-data">
@csrf
<!-- Hidden inputs for Base64 cropped image & Remove Request -->
<input type="hidden" name="cropped_image_data" id="cropped_image_data">
<input type="hidden" name="remove_profile_image" id="remove_profile_image" value="0">
<div class="modal-body p-4">
<!-- Profile Picture Upload, Cropper & Emoji Avatar Section -->
<div class="mb-4 text-center p-4 rounded-4 bg-light border">
<label class="form-label fw-bold text-dark d-block mb-3">Profile Picture</label>
<div class="d-flex flex-column align-items-center mb-3">
<!-- GUARANTEED SINGLE CIRCLE FRAME CONTAINER -->
<div class="rounded-circle shadow border border-4 border-white overflow-hidden"
style="width: 130px; height: 130px; background: var(--theme-navy); position: relative; margin: 0 auto;">
<img id="modal_avatar_img"
src="{{ !empty($student->image) ? asset($student->image) : '' }}"
alt="{{ $student->full_name }}"
style="width: 100%; height: 100%; object-fit: cover; position: absolute; top: 0; left: 0; z-index: 2; {{ !empty($student->image) ? 'display: block;' : 'display: none;' }}"
onerror="this.style.display='none'; document.getElementById('modal_avatar_placeholder_inner').style.display='flex';">
<div id="modal_avatar_placeholder_inner"
class="w-100 h-100 d-flex align-items-center justify-content-center fw-bold position-absolute top-0 start-0"
style="background: var(--theme-navy); color: var(--theme-yellow); font-size: 54px; z-index: 1;">
<span id="avatar_emoji_or_initial">{{ strtoupper(substr($student->full_name ?? 'S', 0, 1)) }}</span>
</div>
</div>
<div id="remove_photo_status" class="badge bg-danger bg-opacity-10 text-danger mt-2 py-1.5 px-3 rounded-pill d-none">
<i class="fa-solid fa-info-circle me-1"></i> Photo will be removed upon saving.
</div>
</div>
<div class="d-flex justify-content-center align-items-center gap-2 flex-wrap mb-3">
<!-- File input button -->
<label class="btn btn-outline-primary btn-sm rounded-pill px-3 py-2 fw-semibold cursor-pointer mb-0">
<i class="fa-solid fa-camera me-1"></i> Choose New Photo
<input type="file" id="profile_image_file_input" class="d-none" accept="image/*">
</label>
<!-- Remove photo button -->
<button type="button" id="btnRemovePhoto" class="btn btn-outline-danger btn-sm rounded-pill px-3 py-2 fw-semibold">
<i class="fa-solid fa-trash-can me-1"></i> Remove Photo
</button>
</div>
<!-- Emoji & Custom Avatar Creator Toolbar -->
<div class="mt-3 pt-3 border-top w-100">
<small class="fw-bold text-secondary d-block mb-2">
<i class="fa-solid fa-icons me-1 text-primary"></i> Or Create a Fun Custom Emoji Avatar:
</small>
<div class="d-flex justify-content-center gap-1.5 flex-wrap mb-2">
<button type="button" class="btn btn-light btn-emoji-picker rounded-circle border shadow-sm p-0 d-inline-flex align-items-center justify-content-center" data-emoji="🎓" style="width: 38px; height: 38px; font-size: 1.2rem;" title="Graduate">🎓</button>
<button type="button" class="btn btn-light btn-emoji-picker rounded-circle border shadow-sm p-0 d-inline-flex align-items-center justify-content-center" data-emoji="👨‍🔧" style="width: 38px; height: 38px; font-size: 1.2rem;" title="Mechanic Tech">👨‍🔧</button>
<button type="button" class="btn btn-light btn-emoji-picker rounded-circle border shadow-sm p-0 d-inline-flex align-items-center justify-content-center" data-emoji="👩‍🔧" style="width: 38px; height: 38px; font-size: 1.2rem;" title="Female Tech">👩‍🔧</button>
<button type="button" class="btn btn-light btn-emoji-picker rounded-circle border shadow-sm p-0 d-inline-flex align-items-center justify-content-center" data-emoji="🏎️" style="width: 38px; height: 38px; font-size: 1.2rem;" title="Race Car">🏎️</button>
<button type="button" class="btn btn-light btn-emoji-picker rounded-circle border shadow-sm p-0 d-inline-flex align-items-center justify-content-center" data-emoji="👨‍💻" style="width: 38px; height: 38px; font-size: 1.2rem;" title="IT Student">👨‍💻</button>
<button type="button" class="btn btn-light btn-emoji-picker rounded-circle border shadow-sm p-0 d-inline-flex align-items-center justify-content-center" data-emoji="" style="width: 38px; height: 38px; font-size: 1.2rem;" title="Speedster"></button>
<button type="button" class="btn btn-light btn-emoji-picker rounded-circle border shadow-sm p-0 d-inline-flex align-items-center justify-content-center" data-emoji="😎" style="width: 38px; height: 38px; font-size: 1.2rem;" title="Cool Student">😎</button>
<button type="button" class="btn btn-light btn-emoji-picker rounded-circle border shadow-sm p-0 d-inline-flex align-items-center justify-content-center" data-emoji="🚀" style="width: 38px; height: 38px; font-size: 1.2rem;" title="High Achiever">🚀</button>
<button type="button" class="btn btn-light btn-emoji-picker rounded-circle border shadow-sm p-0 d-inline-flex align-items-center justify-content-center" data-emoji="🏆" style="width: 38px; height: 38px; font-size: 1.2rem;" title="Champion">🏆</button>
<button type="button" class="btn btn-light btn-emoji-picker rounded-circle border shadow-sm p-0 d-inline-flex align-items-center justify-content-center" data-emoji="" style="width: 38px; height: 38px; font-size: 1.2rem;" title="Star"></button>
</div>
<div class="d-flex justify-content-center align-items-center gap-2 mt-2">
<small class="text-muted" style="font-size: 0.78rem;">Background Color:</small>
<button type="button" class="btn-avatar-color rounded-circle border border-2 border-white shadow-sm p-0" data-color="#1E233E" style="width: 26px; height: 26px; background: #1E233E;" title="Navy Blue"></button>
<button type="button" class="btn-avatar-color rounded-circle border border-2 border-white shadow-sm p-0" data-color="#822424" style="width: 26px; height: 26px; background: #822424;" title="Accent Red"></button>
<button type="button" class="btn-avatar-color rounded-circle border border-2 border-white shadow-sm p-0" data-color="#064E3B" style="width: 26px; height: 26px; background: #064E3B;" title="Emerald Green"></button>
<button type="button" class="btn-avatar-color rounded-circle border border-2 border-white shadow-sm p-0" data-color="#4F46E5" style="width: 26px; height: 26px; background: #4F46E5;" title="Indigo"></button>
<button type="button" class="btn-avatar-color rounded-circle border border-2 border-white shadow-sm p-0" data-color="#0F172A" style="width: 26px; height: 26px; background: #0F172A;" title="Dark Charcoal"></button>
</div>
</div>
</div>
<h6 class="fw-bold mb-3 pb-2 border-bottom" style="color: var(--theme-navy);">
<i class="fa-solid fa-id-card text-danger me-2"></i> Personal Details
</h6>
<div class="row g-3 mb-4">
<div class="col-md-6">
<label for="full_name" class="form-label fw-semibold small text-secondary">Full Name <span class="text-danger">*</span></label>
<input type="text" name="full_name" id="full_name" class="form-control rounded-3" value="{{ old('full_name', $student->full_name) }}" required>
</div>
<div class="col-md-6">
<label for="email" class="form-label fw-semibold small text-secondary">Email Address <span class="text-danger">*</span></label>
<input type="email" name="email" id="email" class="form-control rounded-3" value="{{ old('email', $student->email) }}" required>
</div>
<div class="col-md-6">
<label for="phone" class="form-label fw-semibold small text-secondary">Phone Number</label>
<input type="text" name="phone" id="phone" class="form-control rounded-3" value="{{ old('phone', $student->phone) }}">
</div>
<div class="col-md-6">
<label for="nic_passport" class="form-label fw-semibold small text-secondary">NIC / Passport Number</label>
<input type="text" name="nic_passport" id="nic_passport" class="form-control rounded-3" value="{{ old('nic_passport', $student->nic_passport) }}">
</div>
<div class="col-md-6">
<label for="date_of_birth" class="form-label fw-semibold small text-secondary">Date of Birth</label>
<input type="date" name="date_of_birth" id="date_of_birth" class="form-control rounded-3" value="{{ old('date_of_birth', $student->date_of_birth) }}">
</div>
<div class="col-md-6">
<label for="gender" class="form-label fw-semibold small text-secondary">Gender</label>
<select name="gender" id="gender" class="form-select rounded-3">
<option value="Male" {{ strtolower($student->gender ?? '') == 'male' ? 'selected' : '' }}>Male</option>
<option value="Female" {{ strtolower($student->gender ?? '') == 'female' ? 'selected' : '' }}>Female</option>
<option value="Other" {{ strtolower($student->gender ?? '') == 'other' ? 'selected' : '' }}>Other</option>
</select>
</div>
</div>
<h6 class="fw-bold mb-3 pb-2 border-bottom" style="color: var(--theme-navy);">
<i class="fa-solid fa-graduation-cap text-danger me-2"></i> Educational Background
</h6>
<div class="row g-3">
<div class="col-md-4">
<label for="qualification" class="form-label fw-semibold small text-secondary">Qualification</label>
<input type="text" name="qualification" id="qualification" class="form-control rounded-3" value="{{ old('qualification', $student->qualification) }}">
</div>
<div class="col-md-4">
<label for="institute" class="form-label fw-semibold small text-secondary">Institute</label>
<input type="text" name="institute" id="institute" class="form-control rounded-3" value="{{ old('institute', $student->institute) }}">
</div>
<div class="col-md-4">
<label for="year_completed" class="form-label fw-semibold small text-secondary">Year Completed</label>
<input type="text" name="year_completed" id="year_completed" class="form-control rounded-3" value="{{ old('year_completed', $student->year_completed) }}">
</div>
</div>
</div>
<div class="modal-footer bg-light p-3">
<button type="button" class="btn btn-light rounded-3 px-4 fw-bold border" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn text-white rounded-3 px-4 fw-bold" style="background: var(--theme-red); border: none;">
<i class="fa-solid fa-check me-2"></i> Save Changes
</button>
</div>
</form>
</div>
</div>
</div>
<!-- IMAGE CROPPER MODAL -->
<div class="modal fade" id="cropImageModal" data-bs-backdrop="static" tabindex="-1" aria-labelledby="cropImageModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content border-0 rounded-4 shadow-lg overflow-hidden">
<div class="modal-header text-white p-3" style="background: linear-gradient(135deg, var(--theme-navy) 0%, var(--theme-navy-dark) 100%);">
<h6 class="modal-title fw-bold" id="cropImageModalLabel">
<i class="fa-solid fa-crop-simple me-2" style="color: var(--theme-yellow);"></i> Crop & Adjust Profile Picture
</h6>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body p-3 text-center">
<div class="img-container mb-3" style="max-height: 380px; overflow: hidden; background: #0f172a; border-radius: 12px;">
<img id="cropper_image_target" src="" style="max-width: 100%; display: block; margin: 0 auto;">
</div>
<!-- Crop Control Toolbar -->
<div class="d-flex justify-content-center gap-2 mb-2">
<button type="button" class="btn btn-light btn-sm rounded-circle shadow-sm" id="btnZoomIn" title="Zoom In">
<i class="fa-solid fa-magnifying-glass-plus"></i>
</button>
<button type="button" class="btn btn-light btn-sm rounded-circle shadow-sm" id="btnZoomOut" title="Zoom Out">
<i class="fa-solid fa-magnifying-glass-minus"></i>
</button>
<button type="button" class="btn btn-light btn-sm rounded-circle shadow-sm" id="btnRotateRight" title="Rotate 90°">
<i class="fa-solid fa-rotate-right"></i>
</button>
<button type="button" class="btn btn-light btn-sm rounded-circle shadow-sm" id="btnResetCrop" title="Reset">
<i class="fa-solid fa-arrows-rotate"></i>
</button>
</div>
</div>
<div class="modal-footer bg-light p-2.5">
<button type="button" class="btn btn-light btn-sm rounded-3 px-3 fw-bold border" data-bs-dismiss="modal">Cancel</button>
<button type="button" id="btnApplyCrop" class="btn btn-primary btn-sm rounded-3 px-4 fw-bold" style="background: var(--theme-navy); border: none; color: var(--theme-yellow);">
<i class="fa-solid fa-check me-1"></i> Crop & Apply
</button>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
let cropper = null;
let selectedBgColor = '#1E233E';
let currentEmoji = '🎓';
const fileInput = document.getElementById('profile_image_file_input');
const cropperImgTarget = document.getElementById('cropper_image_target');
const croppedImageDataInput = document.getElementById('cropped_image_data');
const removeProfileImageInput = document.getElementById('remove_profile_image');
const modalAvatarImg = document.getElementById('modal_avatar_img');
const modalAvatarPlaceholder = document.getElementById('modal_avatar_placeholder_inner');
const avatarEmojiOrInitial = document.getElementById('avatar_emoji_or_initial');
const removePhotoStatus = document.getElementById('remove_photo_status');
const btnRemovePhoto = document.getElementById('btnRemovePhoto');
const editProfileModalEl = document.getElementById('editProfileModal');
const cropModalEl = document.getElementById('cropImageModal');
let cropModal = null;
if (cropModalEl) {
cropModal = new bootstrap.Modal(cropModalEl, { backdrop: 'static' });
}
// 1. File Selected -> Open Cropper Modal
if (fileInput) {
fileInput.addEventListener('change', function (e) {
const files = e.target.files;
if (files && files.length > 0) {
const file = files[0];
if (!file.type.match('image.*')) {
alert('Please select an image file (JPG, PNG, GIF).');
return;
}
const reader = new FileReader();
reader.onload = function (evt) {
cropperImgTarget.src = evt.target.result;
// Show Cropper Modal
if (cropModal) {
cropModal.show();
}
};
reader.readAsDataURL(file);
}
});
}
// 2. Initialize Cropper when Crop Modal is fully shown
if (cropModalEl) {
cropModalEl.addEventListener('shown.bs.modal', function () {
if (cropper) {
cropper.destroy();
}
cropper = new Cropper(cropperImgTarget, {
aspectRatio: 1,
viewMode: 1,
autoCropArea: 0.9,
responsive: true,
restore: false,
checkCrossOrigin: false,
background: false,
});
});
cropModalEl.addEventListener('hidden.bs.modal', function () {
if (cropper) {
cropper.destroy();
cropper = null;
}
fileInput.value = '';
});
}
// Toolbar Actions
document.getElementById('btnZoomIn')?.addEventListener('click', function () {
cropper && cropper.zoom(0.1);
});
document.getElementById('btnZoomOut')?.addEventListener('click', function () {
cropper && cropper.zoom(-0.1);
});
document.getElementById('btnRotateRight')?.addEventListener('click', function () {
cropper && cropper.rotate(90);
});
document.getElementById('btnResetCrop')?.addEventListener('click', function () {
cropper && cropper.reset();
});
// 3. Apply Cropped Canvas
document.getElementById('btnApplyCrop')?.addEventListener('click', function () {
if (!cropper) return;
const canvas = cropper.getCroppedCanvas({
width: 350,
height: 350,
imageSmoothingEnabled: true,
imageSmoothingQuality: 'high',
});
if (canvas) {
const base64Image = canvas.toDataURL('image/png');
croppedImageDataInput.value = base64Image;
removeProfileImageInput.value = '0';
// Live preview update in Edit Profile Modal
modalAvatarImg.src = base64Image;
modalAvatarImg.style.display = 'block';
if (removePhotoStatus) {
removePhotoStatus.classList.add('d-none');
}
// Close Crop Modal
if (cropModal) {
cropModal.hide();
}
}
});
// 4. Remove Photo Action
if (btnRemovePhoto) {
btnRemovePhoto.addEventListener('click', function () {
removeProfileImageInput.value = '1';
croppedImageDataInput.value = '';
fileInput.value = '';
modalAvatarImg.style.display = 'none';
if (removePhotoStatus) {
removePhotoStatus.classList.remove('d-none');
}
});
}
// 5. Generate Custom Emoji Canvas Avatar
function generateEmojiAvatar(emojiSymbol, bgColor) {
const canvas = document.createElement('canvas');
canvas.width = 300;
canvas.height = 300;
const ctx = canvas.getContext('2d');
// Draw colored circle
ctx.beginPath();
ctx.arc(150, 150, 150, 0, Math.PI * 2);
ctx.fillStyle = bgColor;
ctx.fill();
// Draw centered emoji
ctx.font = '140px "Segoe UI Emoji", "Apple Color Emoji", sans-serif';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(emojiSymbol, 150, 158);
const base64Image = canvas.toDataURL('image/png');
croppedImageDataInput.value = base64Image;
removeProfileImageInput.value = '0';
// Update modal avatar preview
modalAvatarImg.src = base64Image;
modalAvatarImg.style.display = 'block';
if (removePhotoStatus) {
removePhotoStatus.classList.add('d-none');
}
}
// Emoji Picker Clicks
document.querySelectorAll('.btn-emoji-picker').forEach(function (btn) {
btn.addEventListener('click', function () {
currentEmoji = this.getAttribute('data-emoji');
generateEmojiAvatar(currentEmoji, selectedBgColor);
});
});
// Background Color Clicks
document.querySelectorAll('.btn-avatar-color').forEach(function (btn) {
btn.addEventListener('click', function () {
selectedBgColor = this.getAttribute('data-color');
generateEmojiAvatar(currentEmoji, selectedBgColor);
});
});
});
</script>
@endsection