| 1 | <!DOCTYPE html>
|
|---|
| 2 | <html lang="en">
|
|---|
| 3 | <head>
|
|---|
| 4 | <meta charset="UTF-8">
|
|---|
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|---|
| 6 | <title>Login - Handcraft Marketplace</title>
|
|---|
| 7 | <link rel="stylesheet" href="style.css">
|
|---|
| 8 | </head>
|
|---|
| 9 | <body>
|
|---|
| 10 | <header>
|
|---|
| 11 | <div class="logo-container">
|
|---|
| 12 | <img src="../images/administrative/logo.jpg" alt="Handcraft Marketplace Logo" onerror="this.style.display='none'">
|
|---|
| 13 | <h1>🎨 Handcraft Marketplace</h1>
|
|---|
| 14 | </div>
|
|---|
| 15 | <nav>
|
|---|
| 16 | <ul>
|
|---|
| 17 | <li><a href="index.html">Home</a></li>
|
|---|
| 18 | <li><a href="products.html">Products</a></li>
|
|---|
| 19 | <li><a href="login.html" class="active">Login</a></li>
|
|---|
| 20 | <li><a href="register.html">Register</a></li>
|
|---|
| 21 | </ul>
|
|---|
| 22 | </nav>
|
|---|
| 23 | </header>
|
|---|
| 24 |
|
|---|
| 25 | <main>
|
|---|
| 26 | <div class="form-container">
|
|---|
| 27 | <h2>Login to Your Account</h2>
|
|---|
| 28 | <p class="form-subtitle">Welcome back! Please enter your credentials</p>
|
|---|
| 29 |
|
|---|
| 30 | <form id="login-form" class="form">
|
|---|
| 31 | <div class="form-group">
|
|---|
| 32 | <label for="email">Email or Username</label>
|
|---|
| 33 | <input type="text" id="email" name="email" required>
|
|---|
| 34 | </div>
|
|---|
| 35 |
|
|---|
| 36 | <div class="form-group">
|
|---|
| 37 | <label for="password">Password</label>
|
|---|
| 38 | <input type="password" id="password" name="password" required>
|
|---|
| 39 | </div>
|
|---|
| 40 |
|
|---|
| 41 | <div class="form-group">
|
|---|
| 42 | <button type="submit" class="btn-primary btn-full">Login</button>
|
|---|
| 43 | </div>
|
|---|
| 44 | </form>
|
|---|
| 45 |
|
|---|
| 46 | <div class="form-footer">
|
|---|
| 47 | <p>Don't have an account? <a href="register.html">Register as client</a></p>
|
|---|
| 48 | <p>Want to sell? <a href="register-store.html">Register your store</a></p>
|
|---|
| 49 | </div>
|
|---|
| 50 | </div>
|
|---|
| 51 | </main>
|
|---|
| 52 |
|
|---|
| 53 | <div id="2fa-modal" class="modal" style="display: none;">
|
|---|
| 54 | <div class="modal-content">
|
|---|
| 55 | <span class="close">×</span>
|
|---|
| 56 | <h2>Two-Factor Authentication</h2>
|
|---|
| 57 | <p>We've sent a verification code to <span id="2fa-email"></span></p>
|
|---|
| 58 | <p class="code-expiry">Code expires in 30 seconds</p>
|
|---|
| 59 | <div class="form-group">
|
|---|
| 60 | <label for="2fa-code">Enter 6-digit code:</label>
|
|---|
| 61 | <input type="text" id="2fa-code" maxlength="6" placeholder="000000">
|
|---|
| 62 | </div>
|
|---|
| 63 | <div class="form-group">
|
|---|
| 64 | <button id="verify-2fa-btn" class="btn-primary">Verify</button>
|
|---|
| 65 | </div>
|
|---|
| 66 | <p class="resend-link">Didn't receive code? <a href="#" id="resend-2fa">Resend</a></p>
|
|---|
| 67 | </div>
|
|---|
| 68 | </div>
|
|---|
| 69 |
|
|---|
| 70 | <footer>
|
|---|
| 71 | <div class="footer-content">
|
|---|
| 72 | <div class="footer-section">
|
|---|
| 73 | <h3>Handcraft Marketplace</h3>
|
|---|
| 74 | <p>Connecting artisans with buyers worldwide</p>
|
|---|
| 75 | </div>
|
|---|
| 76 | <div class="footer-section">
|
|---|
| 77 | <h3>Quick Links</h3>
|
|---|
| 78 | <ul>
|
|---|
| 79 | <li><a href="index.html">Home</a></li>
|
|---|
| 80 | <li><a href="products.html">Products</a></li>
|
|---|
| 81 | <li><a href="login.html">Login</a></li>
|
|---|
| 82 | <li><a href="register.html">Register</a></li>
|
|---|
| 83 | </ul>
|
|---|
| 84 | </div>
|
|---|
| 85 | <div class="footer-section">
|
|---|
| 86 | <h3>For Sellers</h3>
|
|---|
| 87 | <ul>
|
|---|
| 88 | <li><a href="register-store.html">Open a Store</a></li>
|
|---|
| 89 | </ul>
|
|---|
| 90 | </div>
|
|---|
| 91 | <div class="footer-section">
|
|---|
| 92 | <h3>Contact</h3>
|
|---|
| 93 | <p>Email: support@handcraft.com</p>
|
|---|
| 94 | </div>
|
|---|
| 95 | </div>
|
|---|
| 96 | <div class="footer-bottom">
|
|---|
| 97 | <p>© 2025 Handcraft Marketplace. All rights reserved.</p>
|
|---|
| 98 | </div>
|
|---|
| 99 | </footer>
|
|---|
| 100 |
|
|---|
| 101 | <script src="script.js"></script>
|
|---|
| 102 | <script>
|
|---|
| 103 | document.addEventListener('DOMContentLoaded', () => {
|
|---|
| 104 | const loginForm = document.getElementById('login-form');
|
|---|
| 105 | const modal = document.getElementById('2fa-modal');
|
|---|
| 106 | const closeBtn = document.querySelector('.close');
|
|---|
| 107 | const verifyBtn = document.getElementById('verify-2fa-btn');
|
|---|
| 108 | const resendLink = document.getElementById('resend-2fa');
|
|---|
| 109 | const twoFACode = document.getElementById('2fa-code');
|
|---|
| 110 | let currentEmail = '';
|
|---|
| 111 |
|
|---|
| 112 | loginForm.addEventListener('submit', async (e) => {
|
|---|
| 113 | e.preventDefault();
|
|---|
| 114 |
|
|---|
| 115 | const formData = {
|
|---|
| 116 | email: document.getElementById('email').value,
|
|---|
| 117 | password: document.getElementById('password').value
|
|---|
| 118 | };
|
|---|
| 119 |
|
|---|
| 120 | try {
|
|---|
| 121 | const response = await fetch('/api/login', {
|
|---|
| 122 | method: 'POST',
|
|---|
| 123 | headers: { 'Content-Type': 'application/json' },
|
|---|
| 124 | body: JSON.stringify(formData)
|
|---|
| 125 | });
|
|---|
| 126 |
|
|---|
| 127 | const data = await response.json();
|
|---|
| 128 |
|
|---|
| 129 | if (data.success) {
|
|---|
| 130 | if (data.requires2FA) {
|
|---|
| 131 | currentEmail = data.email;
|
|---|
| 132 | document.getElementById('2fa-email').textContent = currentEmail;
|
|---|
| 133 | modal.style.display = 'block';
|
|---|
| 134 |
|
|---|
| 135 | if (data.developmentCode) {
|
|---|
| 136 | console.log('Development 2FA code:', data.developmentCode);
|
|---|
| 137 | }
|
|---|
| 138 | } else {
|
|---|
| 139 | window.location.href = data.redirectTo || 'dashboard.html';
|
|---|
| 140 | }
|
|---|
| 141 | } else {
|
|---|
| 142 | alert(data.message || 'Login failed');
|
|---|
| 143 | }
|
|---|
| 144 | } catch (error) {
|
|---|
| 145 | console.error('Login error:', error);
|
|---|
| 146 | alert('An error occurred during login');
|
|---|
| 147 | }
|
|---|
| 148 | });
|
|---|
| 149 |
|
|---|
| 150 | verifyBtn.addEventListener('click', async () => {
|
|---|
| 151 | const code = twoFACode.value;
|
|---|
| 152 |
|
|---|
| 153 | if (!code || code.length !== 6) {
|
|---|
| 154 | alert('Please enter a valid 6-digit code');
|
|---|
| 155 | return;
|
|---|
| 156 | }
|
|---|
| 157 |
|
|---|
| 158 | try {
|
|---|
| 159 | const response = await fetch('/api/verify-2fa', {
|
|---|
| 160 | method: 'POST',
|
|---|
| 161 | headers: { 'Content-Type': 'application/json' },
|
|---|
| 162 | body: JSON.stringify({
|
|---|
| 163 | email: currentEmail,
|
|---|
| 164 | code: code
|
|---|
| 165 | })
|
|---|
| 166 | });
|
|---|
| 167 |
|
|---|
| 168 | const data = await response.json();
|
|---|
| 169 |
|
|---|
| 170 | if (data.success) {
|
|---|
| 171 | if (data.requiresPasswordChange) {
|
|---|
| 172 | window.location.href = 'change-password.html?forced=true';
|
|---|
| 173 | } else {
|
|---|
| 174 | window.location.href = data.redirectTo || 'dashboard.html';
|
|---|
| 175 | }
|
|---|
| 176 | } else {
|
|---|
| 177 | alert(data.message || 'Verification failed');
|
|---|
| 178 | }
|
|---|
| 179 | } catch (error) {
|
|---|
| 180 | console.error('2FA verification error:', error);
|
|---|
| 181 | alert('An error occurred during verification');
|
|---|
| 182 | }
|
|---|
| 183 | });
|
|---|
| 184 |
|
|---|
| 185 | resendLink.addEventListener('click', async (e) => {
|
|---|
| 186 | e.preventDefault();
|
|---|
| 187 |
|
|---|
| 188 | try {
|
|---|
| 189 | const response = await fetch('/api/resend-2fa', {
|
|---|
| 190 | method: 'POST',
|
|---|
| 191 | headers: { 'Content-Type': 'application/json' },
|
|---|
| 192 | body: JSON.stringify({ email: currentEmail })
|
|---|
| 193 | });
|
|---|
| 194 |
|
|---|
| 195 | const data = await response.json();
|
|---|
| 196 |
|
|---|
| 197 | if (data.success) {
|
|---|
| 198 | alert('New verification code sent!');
|
|---|
| 199 | if (data.developmentCode) {
|
|---|
| 200 | console.log('New development code:', data.developmentCode);
|
|---|
| 201 | }
|
|---|
| 202 | } else {
|
|---|
| 203 | alert(data.message || 'Failed to resend code');
|
|---|
| 204 | }
|
|---|
| 205 | } catch (error) {
|
|---|
| 206 | console.error('Resend error:', error);
|
|---|
| 207 | alert('An error occurred');
|
|---|
| 208 | }
|
|---|
| 209 | });
|
|---|
| 210 |
|
|---|
| 211 | closeBtn.addEventListener('click', () => {
|
|---|
| 212 | modal.style.display = 'none';
|
|---|
| 213 | });
|
|---|
| 214 |
|
|---|
| 215 | window.addEventListener('click', (event) => {
|
|---|
| 216 | if (event.target === modal) {
|
|---|
| 217 | modal.style.display = 'none';
|
|---|
| 218 | }
|
|---|
| 219 | });
|
|---|
| 220 | });
|
|---|
| 221 | </script>
|
|---|
| 222 | </body>
|
|---|
| 223 | </html> |
|---|