399 lines
22 KiB
PHP
399 lines
22 KiB
PHP
@extends('layouts.masterbeta')
|
|
|
|
@section('title', 'Click ERP - My Profile')
|
|
|
|
@push('styles')
|
|
<style>
|
|
.profile-avatar-wrapper { position: relative; width: 120px; height: 120px; margin: 0 auto; }
|
|
.profile-avatar { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; border: 4px solid #fff; box-shadow: 0 4px 10px rgba(0,0,0,0.1); }
|
|
.profile-avatar-placeholder { width: 100%; height: 100%; border-radius: 50%; background-color: #f8f9fc; display: flex; align-items: center; justify-content: center; font-size: 2.5rem; font-weight: bold; color: #5c4df0; border: 4px solid #fff; box-shadow: 0 4px 10px rgba(0,0,0,0.1); }
|
|
.btn-upload-avatar { position: absolute; bottom: 0; right: 0; background: #5c4df0; color: #fff; width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center; justify-content: center; cursor: pointer; border: 2px solid #fff; transition: all 0.2s; }
|
|
.btn-upload-avatar:hover { background: #4338ca; transform: scale(1.1); }
|
|
</style>
|
|
@endpush
|
|
|
|
@section('breadcrumbs')
|
|
<a href="{{ url('/') }}" class="text-secondary text-decoration-none"><i class="bi bi-house me-2"></i></a>
|
|
<i class="bi bi-chevron-right text-secondary me-2" style="font-size: 0.8rem;"></i>
|
|
<span class="fw-bold" style="font-size: 0.95rem;">My Profile</span>
|
|
@endsection
|
|
|
|
@section('content')
|
|
<div class="mb-4">
|
|
<h4 class="fw-bold mb-1">Personal Settings</h4>
|
|
<p class="text-secondary mb-0" style="font-size: 0.9rem;">Manage your profile information and emergency contacts.</p>
|
|
</div>
|
|
|
|
<div class="row g-4">
|
|
<!-- Left Column: Organizational Info & Quick Links -->
|
|
<div class="col-lg-4">
|
|
<div class="content-card p-4 text-center mb-4">
|
|
<form id="avatarForm" enctype="multipart/form-data">
|
|
<div class="profile-avatar-wrapper mb-3">
|
|
@if($staff->profile_pic)
|
|
<img src="{{ asset('public/storage/' . $staff->profile_pic) }}" class="profile-avatar" id="avatarPreviewDisplay" alt="{{ $staff->name }}">
|
|
@else
|
|
@php
|
|
$words = explode(' ', $staff->name);
|
|
$initials = strtoupper(substr($words[0], 0, 1) . (isset($words[1]) ? substr($words[1], 0, 1) : ''));
|
|
@endphp
|
|
<div class="profile-avatar-placeholder" id="avatarPreviewDisplay">{{ $initials }}</div>
|
|
@endif
|
|
<label for="profilePhoto" class="btn-upload-avatar" title="Update Photo">
|
|
<i class="bi bi-camera-fill" style="font-size: 0.9rem;"></i>
|
|
</label>
|
|
<input type="file" id="profilePhoto" name="photo" class="d-none" accept=".jpg,.jpeg,.png">
|
|
</div>
|
|
</form>
|
|
|
|
<h5 class="fw-bold mb-1 text-dark">{{ $staff->name }}</h5>
|
|
<p class="text-secondary small mb-3">{{ $staff->designation ?? 'Staff Member' }}</p>
|
|
|
|
<span class="badge {{ $staff->status == 'ACTIVE' ? 'bg-success' : 'bg-warning' }} bg-opacity-10 text-{{ $staff->status == 'ACTIVE' ? 'success' : 'warning' }} px-3 py-2 rounded-pill mb-4">
|
|
{{ $staff->status }}
|
|
</span>
|
|
|
|
<div class="border-top pt-4 text-start">
|
|
<h6 class="fw-bold text-secondary mb-3 text-uppercase" style="font-size: 0.75rem; letter-spacing: 1px;">Work Information</h6>
|
|
|
|
<div class="d-flex align-items-center mb-3">
|
|
<div class="bg-light p-2 rounded me-3 text-secondary"><i class="bi bi-envelope"></i></div>
|
|
<div>
|
|
<div class="small text-secondary fw-semibold" style="font-size: 0.7rem;">WORK EMAIL</div>
|
|
<div class="fw-medium text-dark small">{{ $staff->email }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-flex align-items-center mb-3">
|
|
<div class="bg-light p-2 rounded me-3 text-secondary"><i class="bi bi-person-badge"></i></div>
|
|
<div>
|
|
<div class="small text-secondary fw-semibold" style="font-size: 0.7rem;">STAFF ID</div>
|
|
<div class="fw-medium text-dark small">{{ $staff->staff_id ?? 'N/A' }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-flex align-items-center mb-4">
|
|
<div class="bg-light p-2 rounded me-3 text-secondary"><i class="bi bi-calendar-check"></i></div>
|
|
<div>
|
|
<div class="small text-secondary fw-semibold" style="font-size: 0.7rem;">HIRE DATE</div>
|
|
<div class="fw-medium text-dark small">{{ $staff->hire_date ? date('M d, Y', strtotime($staff->hire_date)) : 'N/A' }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<a href="{{ route('leave.my_leave') }}" class="btn w-100 fw-bold border text-primary d-flex justify-content-between align-items-center" style="background-color: #f8f9fc;">
|
|
<span><i class="bi bi-airplane me-2"></i> Leave Management</span>
|
|
<span class="badge bg-primary rounded-pill">{{ $staff->annual_leave_balance }} Days</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Right Column: Editable Form & Emergency Contacts -->
|
|
<div class="col-lg-8">
|
|
<!-- Personal Details Form -->
|
|
<div class="content-card p-4 mb-4">
|
|
<h5 class="fw-bold mb-4 border-bottom pb-3">Edit Profile Details</h5>
|
|
|
|
<form id="profileForm">
|
|
@csrf
|
|
@method('PUT')
|
|
|
|
<div class="row g-4 mb-4">
|
|
<div class="col-md-6">
|
|
<label class="form-label text-secondary fw-semibold small">Full Name</label>
|
|
<input type="text" class="form-control" name="name" value="{{ $staff->name }}" required>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<label class="form-label text-secondary fw-semibold small">Phone Number</label>
|
|
<input type="text" class="form-control" name="phone" value="{{ $staff->phone }}">
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<label class="form-label text-secondary fw-semibold small">Personal Email</label>
|
|
<input type="email" class="form-control" name="personal_email" value="{{ $staff->personal_email }}" placeholder="Alternate contact email">
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<label class="form-label text-secondary fw-semibold small">Location / Country</label>
|
|
<input type="text" class="form-control" name="location_country" value="{{ $staff->location_country }}">
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label text-secondary fw-semibold small">Date of Birth (Month & Day)</label>
|
|
<div class="row g-2">
|
|
@php
|
|
// Extract current month and day if they exist in the DB (e.g., "12-25" or "2026-12-25")
|
|
$currentDob = $staff->dob ? date('m-d', strtotime($staff->dob)) : '--';
|
|
[$currMonth, $currDay] = explode('-', $currentDob) + [null, null];
|
|
@endphp
|
|
|
|
<!-- Month Dropdown -->
|
|
<div class="col-7">
|
|
<select class="form-select" name="birth_month">
|
|
<option value="">Select Month</option>
|
|
<option value="01" {{ $currMonth == '01' ? 'selected' : '' }}>January</option>
|
|
<option value="02" {{ $currMonth == '02' ? 'selected' : '' }}>February</option>
|
|
<option value="03" {{ $currMonth == '03' ? 'selected' : '' }}>March</option>
|
|
<option value="04" {{ $currMonth == '04' ? 'selected' : '' }}>April</option>
|
|
<option value="05" {{ $currMonth == '05' ? 'selected' : '' }}>May</option>
|
|
<option value="06" {{ $currMonth == '06' ? 'selected' : '' }}>June</option>
|
|
<option value="07" {{ $currMonth == '07' ? 'selected' : '' }}>July</option>
|
|
<option value="08" {{ $currMonth == '08' ? 'selected' : '' }}>August</option>
|
|
<option value="09" {{ $currMonth == '09' ? 'selected' : '' }}>September</option>
|
|
<option value="10" {{ $currMonth == '10' ? 'selected' : '' }}>October</option>
|
|
<option value="11" {{ $currMonth == '11' ? 'selected' : '' }}>November</option>
|
|
<option value="12" {{ $currMonth == '12' ? 'selected' : '' }}>December</option>
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Day Dropdown -->
|
|
<div class="col-5">
|
|
<select class="form-select" name="birth_day">
|
|
<option value="">Day</option>
|
|
@for($d = 1; $d <= 31; $d++)
|
|
@php $dayFormatted = str_pad($d, 2, '0', STR_PAD_LEFT); @endphp
|
|
<option value="{{ $dayFormatted }}" {{ $currDay == $dayFormatted ? 'selected' : '' }}>{{ $d }}</option>
|
|
@endfor
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-flex justify-content-end border-top pt-3">
|
|
<button type="submit" id="btnSubmitProfile" class="btn text-white fw-bold px-4" style="background-color: #5c4df0;">
|
|
Save Changes
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Emergency Contacts / Dependents Section -->
|
|
<div class="content-card p-4">
|
|
<div class="d-flex justify-content-between align-items-center mb-4 border-bottom pb-3">
|
|
<h5 class="fw-bold mb-0">Emergency Contacts & Dependents</h5>
|
|
<button class="btn btn-sm text-white fw-bold d-flex align-items-center" style="background-color: #5c4df0; border-radius: 6px;" id="btnOpenDependentModal">
|
|
<i class="bi bi-plus-lg me-1"></i> Add Contact
|
|
</button>
|
|
</div>
|
|
|
|
<div class="table-responsive">
|
|
<table class="table table-custom table-hover mb-0 align-middle">
|
|
<thead>
|
|
<tr>
|
|
<th>Full Name</th>
|
|
<th>Relationship</th>
|
|
<th>Phone</th>
|
|
<th>Medical Notes</th>
|
|
<th class="text-end">Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@forelse($staff->dependents as $dependent)
|
|
<tr>
|
|
<td class="fw-bold text-dark">{{ $dependent->fullname }}</td>
|
|
<td><span class="badge bg-secondary bg-opacity-10 text-dark border">{{ $dependent->relationship }}</span></td>
|
|
<td class="small">{{ $dependent->phone ?? 'N/A' }}</td>
|
|
<td class="small text-secondary text-truncate" style="max-width: 150px;">{{ $dependent->medical_details ?? 'None' }}</td>
|
|
<td class="text-end">
|
|
<div class="d-flex justify-content-end align-items-center"> <!-- Add this wrapper -->
|
|
<button class="btn btn-sm btn-light text-primary me-1 btn-edit-dependent"
|
|
data-id="{{ $dependent->id }}"
|
|
data-fullname="{{ $dependent->fullname }}"
|
|
data-relationship="{{ $dependent->relationship }}"
|
|
data-phone="{{ $dependent->phone }}"
|
|
data-medical_details="{{ $dependent->medical_details }}">
|
|
<i class="bi bi-pencil"></i>
|
|
</button>
|
|
<form action="{{ route('profile.dependent.destroy', $dependent->id) }}" method="POST" class="d-inline">
|
|
@csrf
|
|
@method('DELETE')
|
|
<button type="submit" class="btn btn-sm btn-light text-danger btn-delete-dependent">
|
|
<i class="bi bi-trash"></i>
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
@empty
|
|
<tr>
|
|
<td colspan="5" class="text-center py-4 text-secondary">No emergency contacts added yet.</td>
|
|
</tr>
|
|
@endforelse
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endsection
|
|
|
|
@push('modals')
|
|
<!-- ADD / EDIT EMERGENCY CONTACT MODAL -->
|
|
<div class="modal fade" id="dependentModal" tabindex="-1" aria-hidden="true">
|
|
<div class="modal-dialog modal-dialog-centered">
|
|
<div class="modal-content">
|
|
<div class="modal-header bg-light">
|
|
<h5 class="modal-title fw-bold" id="dependentModalTitle">Add Emergency Contact</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
|
|
<form id="dependentForm">
|
|
@csrf
|
|
<input type="hidden" id="dependentRecordId" name="id">
|
|
<div class="modal-body p-4">
|
|
<div id="dependentModalAlert"></div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label text-secondary fw-semibold small">Full Name *</label>
|
|
<input type="text" class="form-control" id="dep_fullname" name="fullname" required placeholder="e.g. Jane Doe">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label text-secondary fw-semibold small">Relationship *</label>
|
|
<input type="text" class="form-control" id="dep_relationship" name="relationship" required placeholder="e.g. Spouse, Parent, Sibling">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label text-secondary fw-semibold small">Phone Number</label>
|
|
<input type="text" class="form-control" id="dep_phone" name="phone" placeholder="e.g. +233 24 123 4567">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label text-secondary fw-semibold small">Medical Details / Allergies</label>
|
|
<textarea class="form-control" id="dep_medical" name="medical_details" rows="2" placeholder="Optional context..."></textarea>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer bg-light">
|
|
<button type="button" class="btn btn-outline-secondary btn-sm" data-bs-dismiss="modal">Cancel</button>
|
|
<button type="submit" id="btnSubmitDependent" class="btn text-white btn-sm fw-bold px-4" style="background-color: #5c4df0;">Save Contact</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endpush
|
|
|
|
@push('scripts')
|
|
<script>
|
|
$(document).ready(function() {
|
|
// Profile Photo Preview
|
|
$('#profilePhoto').on('change', function(e) {
|
|
if(e.target.files && e.target.files[0]) {
|
|
let reader = new FileReader();
|
|
reader.onload = function(e) {
|
|
$('#avatarPreviewDisplay').replaceWith(`<img src="${e.target.result}" class="profile-avatar" id="avatarPreviewDisplay">`);
|
|
}
|
|
reader.readAsDataURL(e.target.files[0]);
|
|
}
|
|
});
|
|
|
|
// Profile Form Update
|
|
$('#profileForm').on('submit', function(e) {
|
|
e.preventDefault();
|
|
const $btn = $('#btnSubmitProfile');
|
|
const originalText = $btn.html();
|
|
$btn.html('<span class="spinner-border spinner-border-sm me-2"></span> Saving...');
|
|
$btn.prop('disabled', true);
|
|
|
|
let formData = new FormData(this);
|
|
let photoFile = $('#profilePhoto')[0].files[0];
|
|
if (photoFile) formData.append('photo', photoFile);
|
|
|
|
$.ajax({
|
|
url: "{{ route('profile.update') }}",
|
|
type: 'POST',
|
|
data: formData,
|
|
processData: false,
|
|
contentType: false,
|
|
success: function(response) {
|
|
if (response.success) {
|
|
Swal.fire({
|
|
icon: 'success',
|
|
title: 'Updated!',
|
|
text: response.message,
|
|
confirmButtonColor: '#5c4df0'
|
|
}).then(() => location.reload());
|
|
}
|
|
},
|
|
complete: function() {
|
|
$btn.html(originalText).prop('disabled', false);
|
|
}
|
|
});
|
|
});
|
|
|
|
// --- EMERGENCY CONTACT MODAL SCRIPTS ---
|
|
const dependentModal = new bootstrap.Modal(document.getElementById('dependentModal'));
|
|
const $depForm = $('#dependentForm');
|
|
|
|
$('#btnOpenDependentModal').on('click', function() {
|
|
$depForm[0].reset();
|
|
$('#dependentRecordId').val('');
|
|
$('#dependentModalTitle').text('Add Emergency Contact');
|
|
$('#btnSubmitDependent').text('Save Contact');
|
|
dependentModal.show();
|
|
});
|
|
|
|
$('.btn-edit-dependent').on('click', function() {
|
|
const data = $(this).data();
|
|
$depForm[0].reset();
|
|
$('#dependentRecordId').val(data.id);
|
|
$('#dep_fullname').val(data.fullname);
|
|
$('#dep_relationship').val(data.relationship);
|
|
$('#dep_phone').val(data.phone);
|
|
$('#dep_medical').val(data.medical_details);
|
|
|
|
$('#dependentModalTitle').text('Edit Emergency Contact');
|
|
$('#btnSubmitDependent').text('Update Contact');
|
|
dependentModal.show();
|
|
});
|
|
|
|
$depForm.on('submit', function(e) {
|
|
e.preventDefault();
|
|
const $btn = $('#btnSubmitDependent');
|
|
const originalText = $btn.html();
|
|
const recordId = $('#dependentRecordId').val();
|
|
|
|
const url = recordId ? "{{ url('profile/dependents') }}/" + recordId : "{{ route('profile.dependent.store') }}";
|
|
let formData = $depForm.serialize();
|
|
if (recordId) formData += '&_method=PUT';
|
|
|
|
$btn.html('<span class="spinner-border spinner-border-sm me-2"></span> Saving...');
|
|
$btn.prop('disabled', true);
|
|
|
|
$.ajax({
|
|
url: url,
|
|
type: 'POST',
|
|
data: formData,
|
|
success: function(response) {
|
|
if (response.success) {
|
|
dependentModal.hide();
|
|
Swal.fire({
|
|
icon: 'success',
|
|
title: 'Success!',
|
|
text: response.message,
|
|
confirmButtonColor: '#5c4df0'
|
|
}).then(() => location.reload());
|
|
}
|
|
},
|
|
complete: function() {
|
|
$btn.html(originalText).prop('disabled', false);
|
|
}
|
|
});
|
|
});
|
|
|
|
$('.btn-delete-dependent').on('click', function(e) {
|
|
e.preventDefault();
|
|
const $form = $(this).closest('form');
|
|
Swal.fire({
|
|
title: 'Remove Contact?',
|
|
text: "This emergency contact will be deleted.",
|
|
icon: 'warning',
|
|
showCancelButton: true,
|
|
confirmButtonColor: '#ef4444',
|
|
cancelButtonColor: '#6c757d',
|
|
confirmButtonText: 'Yes, remove!'
|
|
}).then((result) => {
|
|
if (result.isConfirmed) $form.submit();
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
@endpush |