all feature
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
@extends('layouts.app')
|
||||
@section('title', 'Đổi Mật Khẩu')
|
||||
|
||||
@section('content')
|
||||
<div class="form-container mt-10">
|
||||
<div class="form-header">
|
||||
<h3 class="form-header-title">Đổi Mật Khẩu</h3>
|
||||
</div>
|
||||
|
||||
<form action="{{ route('user.update_password') }}" method="POST">
|
||||
@csrf
|
||||
<div class="form-body">
|
||||
@if(Auth::user()->first_login == \App\Models\User::FIRST_LOGIN_TRUE)
|
||||
<div class="mb-6 p-4 bg-orange-50 border border-orange-200 text-orange-800 rounded-lg text-sm font-medium leading-relaxed flex items-start gap-2 shadow-sm">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 shrink-0 text-orange-500 mt-0.5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
||||
</svg>
|
||||
<span>Đây là lần đầu tiên bạn đăng nhập vào hệ thống. Để đảm bảo an toàn, hệ thống yêu cầu bạn đổi mật khẩu trước khi sử dụng các chức năng.</span>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="password">Mật khẩu mới <span class="text-red-500">*</span></label>
|
||||
<div class="form-input-group">
|
||||
<span class="form-input-icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M16.5 10.5V6.75a4.5 4.5 0 10-9 0V10.5m-2.812 10.5h14.625c.621 0 1.125-.504 1.125-1.125V11.25c0-.621-.504-1.125-1.125-1.125H3.75c-.621 0-1.125.504-1.125 1.125v7.875c0 .621.504 1.125 1.125 1.125z" />
|
||||
</svg>
|
||||
</span>
|
||||
<input type="password" name="password" id="password" class="form-input form-input-with-icon" required placeholder="Nhập mật khẩu mới">
|
||||
</div>
|
||||
@error('password')<span class="error-text">{{ $message }}</span>@enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="password_confirmation">Xác nhận lại mật khẩu mới <span class="text-red-500">*</span></label>
|
||||
<div class="form-input-group">
|
||||
<span class="form-input-icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
</span>
|
||||
<input type="password" name="password_confirmation" id="password_confirmation" class="form-input form-input-with-icon" required placeholder="Nhập lại mật khẩu mới">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-footer">
|
||||
@if(Auth::user()->first_login != \App\Models\User::FIRST_LOGIN_TRUE)
|
||||
<a href="{{ route('user.dashboard') }}" class="btn-secondary">Hủy bỏ</a>
|
||||
@endif
|
||||
<button type="submit" class="btn-primary">Xác Nhận Đổi Mật Khẩu</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,77 @@
|
||||
@extends('layouts.app')
|
||||
@section('title', 'My Page')
|
||||
|
||||
@section('content')
|
||||
<div class="flex flex-col md:flex-row md:items-center justify-between gap-4 mb-6">
|
||||
<div class="flex items-center gap-4">
|
||||
<h2 class="text-xl font-bold text-text-dark flex items-center gap-2">
|
||||
My Page
|
||||
</h2>
|
||||
<div class="px-4 py-1.5 bg-orange-100 border border-orange-200 rounded-full text-orange-800 font-bold text-sm flex items-center gap-2 shadow-sm">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5 text-orange-500">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 8.25h19.5M2.25 9h19.5m-16.5 5.25h6m-6 2.25h3m-3.75 3h15a2.25 2.25 0 002.25-2.25V6.75A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25v10.5A2.25 2.25 0 004.5 19.5z" />
|
||||
</svg>
|
||||
Thẻ hiện có: <span class="text-lg">{{ $user->card }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form action="{{ route('user.dashboard') }}" method="GET" class="flex items-center gap-2">
|
||||
<input type="month" name="month" value="{{ $selectedMonth }}" class="form-input !py-1.5 !text-sm w-auto border-border-medium rounded">
|
||||
<button type="submit" class="btn-primary !py-1.5 !px-4 text-sm rounded shadow-sm hover:translate-y-[-1px]">Lọc</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="bg-white shadow-sm rounded-xl overflow-hidden border border-border-light">
|
||||
<div class="px-6 py-4 border-b border-border-light bg-gray-50/50">
|
||||
<h3 class="text-lg font-bold text-text-dark">Lịch sử nhận / gửi thẻ (Tháng {{ Carbon\Carbon::parse($selectedMonth)->format('m/Y') }})</h3>
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-border-light text-sm">
|
||||
<thead class="bg-gray-50/80">
|
||||
<tr>
|
||||
<th class="px-6 py-4 text-left text-xs font-bold text-text-light uppercase tracking-wider">Ngày</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-bold text-text-light uppercase tracking-wider">Loại giao dịch</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-bold text-text-light uppercase tracking-wider">Đối tác</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-bold text-text-light uppercase tracking-wider">Số lượng</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="bg-white divide-y divide-border-light">
|
||||
@forelse($administrations as $admin_record)
|
||||
@php
|
||||
$isReceiver = $admin_record->msnv == $user->msnv && $admin_record->received > 0;
|
||||
@endphp
|
||||
<tr class="hover:bg-slate-50 transition-colors">
|
||||
<td class="px-6 py-3 whitespace-nowrap text-text-medium font-medium">{{ Carbon\Carbon::parse($admin_record->date)->format('d/m/Y') }}</td>
|
||||
<td class="px-6 py-3 whitespace-nowrap">
|
||||
@if($isReceiver)
|
||||
<span class="px-3 py-1 inline-flex text-xs leading-5 font-bold rounded-full bg-green-100 text-green-800">Bạn đã nhận thẻ</span>
|
||||
@else
|
||||
<span class="px-3 py-1 inline-flex text-xs leading-5 font-bold rounded-full bg-blue-100 text-blue-800">Bạn gửi tặng thẻ</span>
|
||||
@endif
|
||||
</td>
|
||||
<td class="px-6 py-3 whitespace-nowrap font-bold text-text-dark">
|
||||
@if($isReceiver)
|
||||
Nhận từ: <span class="text-primary">{{ $admin_record->sender }}</span>
|
||||
@else
|
||||
Gửi cho: <span class="text-primary">{{ $admin_record->receiver }}</span>
|
||||
@endif
|
||||
</td>
|
||||
<td class="px-6 py-3 whitespace-nowrap font-extrabold text-lg">
|
||||
@if($isReceiver)
|
||||
<span class="text-green-600">+{{ $admin_record->received }}</span>
|
||||
@else
|
||||
<span class="text-blue-600">-{{ $admin_record->sent }}</span>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="4" class="px-6 py-12 text-center text-text-light font-medium text-base">Bạn chưa có giao dịch gửi/nhận thẻ nào trong tháng này.</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,146 @@
|
||||
@extends('layouts.app')
|
||||
@section('title', 'Gửi Thank Card')
|
||||
|
||||
@section('content')
|
||||
<div class="form-container">
|
||||
<div class="form-header">
|
||||
<h3 class="form-header-title">Gửi Thank Card Tới Đồng Nghiệp</h3>
|
||||
</div>
|
||||
|
||||
<form id="sendCardForm">
|
||||
@csrf
|
||||
|
||||
<div class="form-body">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="receiver">Chọn người nhận <span class="text-red-500">*</span></label>
|
||||
<select name="receiver" id="receiver" class="form-input" required>
|
||||
<option value="" disabled selected>-- Chọn đồng nghiệp --</option>
|
||||
@foreach($users as $u)
|
||||
<option value="{{ $u->msnv }}">{{ $u->msnv }} ({{ $u->mail }})</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="amount">Số lượng thẻ <span class="text-red-500">*</span></label>
|
||||
<select name="amount" id="amount" class="form-input" required>
|
||||
<option value="1">1 Thẻ</option>
|
||||
<option value="2">2 Thẻ</option>
|
||||
<option value="3">3 Thẻ</option>
|
||||
<option value="4">4 Thẻ</option>
|
||||
<option value="{{ \App\Models\Administration::MAX_SEND_CARD_PER_MONTH }}">{{ \App\Models\Administration::MAX_SEND_CARD_PER_MONTH }} Thẻ (Tối đa)</option>
|
||||
</select>
|
||||
<p class="helper-text">Lưu ý: Chỉ được gửi tối đa {{ \App\Models\Administration::MAX_SEND_CARD_PER_MONTH }} thẻ cho cùng 1 người trong 1 tháng.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-footer">
|
||||
<a href="{{ route('user.dashboard') }}" class="btn-secondary">Hủy bỏ</a>
|
||||
<button type="button" id="btnSubmitSend" class="btn-primary">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5 mr-2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6 12L3.269 3.126A59.768 59.768 0 0121.485 12 59.77 59.77 0 013.27 20.876L5.999 12zm0 0h7.5" />
|
||||
</svg>
|
||||
Gửi Card
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Custom Popup Modal -->
|
||||
<x-modal id="customModal" title="Thông báo" maxWidth="md">
|
||||
<p id="modalMessage" class="text-sm text-gray-600 leading-relaxed"></p>
|
||||
|
||||
<x-slot name="footer">
|
||||
<div id="modalActions" class="w-full flex flex-col sm:flex-row-reverse gap-3">
|
||||
<!-- Buttons injected by JS -->
|
||||
</div>
|
||||
</x-slot>
|
||||
</x-modal>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const btnSubmit = document.getElementById('btnSubmitSend');
|
||||
const form = document.getElementById('sendCardForm');
|
||||
|
||||
const modalTitle = document.getElementById('modal-title-customModal');
|
||||
const modalMessage = document.getElementById('modalMessage');
|
||||
const modalActions = document.getElementById('modalActions');
|
||||
|
||||
const showModal = (title, message, isConfirm, confirmCallback) => {
|
||||
modalTitle.textContent = title;
|
||||
modalMessage.innerHTML = message;
|
||||
|
||||
if(isConfirm) {
|
||||
modalTitle.className = "text-lg font-bold text-primary";
|
||||
modalActions.innerHTML = `
|
||||
<button id="btnConfirmOk" class="w-full sm:w-auto btn-primary !px-6 shadow-sm">Xác nhận gửi</button>
|
||||
<button id="btnCancel" class="w-full sm:w-auto btn-secondary !px-6 shadow-sm">Hủy</button>
|
||||
`;
|
||||
document.getElementById('btnCancel').addEventListener('click', () => window.closeModal('customModal'));
|
||||
document.getElementById('btnConfirmOk').addEventListener('click', function() {
|
||||
this.disabled = true;
|
||||
this.innerHTML = '<span class="flex items-center gap-2"><svg class="animate-spin h-4 w-4 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg> Đang xử lý...</span>';
|
||||
confirmCallback();
|
||||
});
|
||||
} else {
|
||||
modalTitle.className = "text-lg font-bold text-red-600";
|
||||
modalActions.innerHTML = `
|
||||
<button id="btnOkOnly" class="w-full sm:w-auto btn-secondary !px-6 shadow-sm">Đóng</button>
|
||||
`;
|
||||
document.getElementById('btnOkOnly').addEventListener('click', () => window.closeModal('customModal'));
|
||||
}
|
||||
|
||||
window.openModal('customModal');
|
||||
};
|
||||
|
||||
btnSubmit.addEventListener('click', function() {
|
||||
if(!form.checkValidity()) {
|
||||
form.reportValidity();
|
||||
return;
|
||||
}
|
||||
|
||||
const receiver = document.getElementById('receiver').value;
|
||||
const amount = document.getElementById('amount').value;
|
||||
|
||||
showModal(
|
||||
'Xác nhận gửi Thank Card',
|
||||
`Bạn có chắc chắn muốn gửi <b>${amount} thẻ</b> cho nhân viên <span class="font-bold text-primary">${receiver}</span> không? <br><br><span class="text-xs text-text-light">Hành động này không thể hoàn tác, tin nhắn CO sẽ được gửi đi!</span>`,
|
||||
true,
|
||||
() => {
|
||||
fetch('{{ route('user.store_send') }}', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
|
||||
},
|
||||
body: JSON.stringify({
|
||||
receiver: receiver,
|
||||
amount: amount
|
||||
})
|
||||
})
|
||||
.then(response => response.json().then(data => ({status: response.status, body: data})))
|
||||
.then(res => {
|
||||
if (res.status === 200 && res.body.success) {
|
||||
alert(res.body.message);
|
||||
window.location.href = '{{ route('user.dashboard') }}';
|
||||
} else {
|
||||
window.closeModal('customModal');
|
||||
setTimeout(() => {
|
||||
showModal('Lỗi Giao Dịch', res.body.message || 'Có lỗi xảy ra, vui lòng thử lại.', false, null);
|
||||
}, 350);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
window.closeModal('customModal');
|
||||
setTimeout(() => {
|
||||
showModal('Lỗi Hệ Thống', 'Không thể kết nối đến máy chủ.', false, null);
|
||||
}, 350);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
Reference in New Issue
Block a user