Files
wms-app/app/login/register.php
T

260 lines
11 KiB
PHP

<?php
require '../session.php';
require '../config.php';
// Redirect if already logged in
if (!empty($_SESSION['login_status'])) {
header('Location: ' . $server_url . 'dashboard/index.php');
exit;
}
// Generate CSRF token for unauthenticated form
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
require '../include_header.php';
?>
<body>
<div class="container d-flex align-items-center justify-content-center min-vh-100 py-5">
<div class="card" style="max-width:520px; width:100%;">
<div class="card-body p-5">
<div class="text-center mb-4">
<a href="<?php echo $server_url?>login/index.php" class="mb-4 d-inline-block">
<img src="data:image/svg+xml,%3csvg%20width='62'%20height='67'%20viewBox='0%200%2062%2067'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M30.604%2066.378L0.00805664%2048.1582V35.7825L30.604%2054.0023V66.378Z'%20fill='%23302C4D'/%3e%3cpath%20d='M61.1996%2048.1582L30.604%2066.378V54.0023L61.1996%2035.7825V48.1582Z'%20fill='%23E66239'/%3e%3cpath%20d='M30.5955%200L0%2018.2198V30.5955L30.5955%2012.3757V0Z'%20fill='%23657E92'/%3e%3cpath%20d='M61.191%2018.2198L30.5955%200V12.3757L61.191%2030.5955V18.2198Z'%20fill='%23A3B2BE'/%3e%3cpath%20d='M30.604%2048.8457L0.00805664%2030.6259V18.2498L30.604%2036.47V48.8457Z'%20fill='%23302C4D'/%3e%3cpath%20d='M61.1996%2030.6259L30.604%2048.8457V36.47L61.1996%2018.2498V30.6259Z'%20fill='%23E66239'/%3e%3c/svg%3e"
alt="" width="36">
<span class="ms-2"><img src="<?php echo $server_url?>assets/images/logo.svg" alt=""></span>
</a>
<h1 class="h5 mb-1">Create your account</h1>
<p class="text-muted small mb-0">Fill in the details below to get started</p>
</div>
<!-- Name row -->
<div class="row g-3 mb-3">
<div class="col-6">
<label class="form-label">First Name <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="name" placeholder="First name" required>
</div>
<div class="col-6">
<label class="form-label">Last Name <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="surname" placeholder="Last name" required>
</div>
</div>
<!-- Username -->
<div class="mb-3">
<label class="form-label">Username <span class="text-danger">*</span></label>
<div class="input-group">
<span class="input-group-text"><i class="ti ti-at"></i></span>
<input type="text" class="form-control" id="username"
placeholder="Choose a username" required
oninput="this.value=this.value.toLowerCase().replace(/[^a-z0-9_]/g,'')">
</div>
<div class="form-text">Lowercase letters, numbers and underscores only.</div>
</div>
<!-- Email -->
<div class="mb-3">
<label class="form-label">Email <span class="text-danger">*</span></label>
<input type="email" class="form-control" id="email" placeholder="your@email.com" required>
</div>
<!-- Password -->
<div class="mb-3">
<label class="form-label">Password <span class="text-danger">*</span></label>
<div class="input-group">
<input type="password" class="form-control" id="password"
placeholder="Choose a strong password"
oninput="on_password_input(this.value)">
<button class="btn btn-outline-secondary toggle-pw" type="button" data-target="password">
<i class="ti ti-eye"></i>
</button>
</div>
<div class="mt-2">
<div class="progress" style="height:5px;">
<div id="pw_strength_bar" class="progress-bar"
style="width:0%;transition:width .25s,background-color .25s;border-radius:4px;"></div>
</div>
<div class="d-flex justify-content-between mt-1">
<small id="pw_strength_label" class="fw-semibold" style="white-space:nowrap;">—</small>
<small id="pw_feedback" class="text-muted text-end"></small>
</div>
</div>
</div>
<!-- Confirm password -->
<div class="mb-4">
<label class="form-label">Confirm Password <span class="text-danger">*</span></label>
<div class="input-group">
<input type="password" class="form-control" id="confirm_password"
placeholder="Repeat your password"
oninput="check_confirm_match()">
<button class="btn btn-outline-secondary toggle-pw" type="button" data-target="confirm_password">
<i class="ti ti-eye"></i>
</button>
</div>
<small id="pw_match_label" class="mt-1 d-block"></small>
</div>
<button class="btn btn-primary w-100 mb-3" id="btn_register" onclick="register()">
<i class="ti ti-user-plus me-1"></i>Create Account
</button>
<!-- Success state (hidden until submit) -->
<div id="success_panel" class="d-none text-center py-3">
<div class="mb-3">
<span class="d-inline-flex align-items-center justify-content-center rounded-circle bg-label-success"
style="width:56px;height:56px;">
<i class="ti ti-mail-check fs-3 text-success"></i>
</span>
</div>
<h6 class="mb-1">Check your inbox!</h6>
<p class="text-muted small mb-0">We've sent a verification link to your email address. Click it to activate your account.</p>
</div>
<p class="text-center text-muted small mb-0">
Already have an account?
<a href="<?php echo $server_url?>login/index.php" class="link-primary">Sign in</a>
</p>
</div>
</div>
</div>
<script>
// ═══════════════════════════════════════════════
// State
// ═══════════════════════════════════════════════
const STRENGTH_LEVELS = [
{ label: 'Very weak', color: '#dc3545', pct: 20 },
{ label: 'Weak', color: '#fd7e14', pct: 40 },
{ label: 'Fair', color: '#ffc107', pct: 60 },
{ label: 'Strong', color: '#198754', pct: 80 },
{ label: 'Very strong', color: '#0d6efd', pct: 100 },
];
var pw_score = -1;
var pw_debounce = null;
var pw_xhr = null;
// ═══════════════════════════════════════════════
// On load
// ═══════════════════════════════════════════════
$(function () {
$(document).on('click', '.toggle-pw', function () {
const $input = $('#' + $(this).data('target'));
const isText = $input.attr('type') === 'text';
$input.attr('type', isText ? 'password' : 'text');
$(this).find('i').toggleClass('ti-eye ti-eye-off');
});
});
// ═══════════════════════════════════════════════
// Password strength
// ═══════════════════════════════════════════════
function on_password_input(pw) {
clearTimeout(pw_debounce);
if (!pw) { reset_strength_ui(); check_confirm_match(); return; }
pw_debounce = setTimeout(() => check_strength(pw), 350);
}
function check_strength(pw) {
if (pw_xhr) pw_xhr.abort();
pw_xhr = $.ajax({
url: '<?php echo $server_url?>setting/api/engine/check_password.php',
type: 'POST',
dataType: 'json',
data: { json: JSON.stringify({
otp: '',
company_id: 0,
action: 'read',
password: pw,
})},
headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') },
success: function (res) {
pw_score = res.score ?? -1;
if (pw_score < 0) { reset_strength_ui(); return; }
const lvl = STRENGTH_LEVELS[pw_score];
$('#pw_strength_bar').css({ width: lvl.pct + '%', backgroundColor: lvl.color });
$('#pw_strength_label').text(lvl.label).css('color', lvl.color);
$('#pw_feedback').text(res.feedback || '');
check_confirm_match();
}
});
}
function reset_strength_ui() {
pw_score = -1;
$('#pw_strength_bar').css({ width: '0%', backgroundColor: '' });
$('#pw_strength_label').text('—').css('color', '');
$('#pw_feedback').text('');
}
function check_confirm_match() {
const np = $('#password').val();
const cp = $('#confirm_password').val();
if (!cp) { $('#pw_match_label').text(''); return; }
if (np === cp) {
$('#pw_match_label').html('<span style="color:#198754;">&#10003; Passwords match</span>');
} else {
$('#pw_match_label').html('<span style="color:#dc3545;">&#10007; Passwords do not match</span>');
}
}
// ═══════════════════════════════════════════════
// Register
// ═══════════════════════════════════════════════
function register() {
const name = $('#name').val().trim();
const surname = $('#surname').val().trim();
const username = $('#username').val().trim();
const email = $('#email').val().trim();
const password = $('#password').val();
const confirm = $('#confirm_password').val();
if (!name || !surname || !username || !email || !password || !confirm) {
bootbox.alert('Please fill in all required fields.');
return;
}
if (password !== confirm) {
bootbox.alert('Passwords do not match.');
return;
}
if (pw_score < 3) {
bootbox.alert('Please choose a stronger password.');
return;
}
ajax_request({
url: '<?php echo $server_url?>login/api/engine/register.php',
autoPrepare: false,
data: { json: JSON.stringify({
otp: '',
company_id: 0,
action: 'create',
name: name,
surname: surname,
username: username,
email: email,
password: password,
confirm_password: confirm,
})},
onSuccess: function (r) {
// Hide form, show success panel
$('input, button, .row, .mb-3, .mb-4').hide();
$('#success_panel').removeClass('d-none');
},
});
}
</script>
</body>
</html>