devanada commited on
Commit
2870d89
·
verified ·
1 Parent(s): f22c61f

Manual changes saved

Browse files
Files changed (5) hide show
  1. components/footer.js +12 -14
  2. components/navbar.js +31 -29
  3. index.html +68 -64
  4. script.js +108 -211
  5. style.css +23 -33
components/footer.js CHANGED
@@ -4,42 +4,42 @@ class CustomFooter extends HTMLElement {
4
  this.shadowRoot.innerHTML = `
5
  <style>
6
  footer {
7
- background: #1a202c;
8
- color: #e2e8f0;
9
- padding: 2rem 1rem;
10
  text-align: center;
11
- margin-top: auto;
12
  }
13
  .footer-content {
14
  max-width: 1200px;
15
  margin: 0 auto;
16
  display: flex;
17
  flex-direction: column;
18
- gap: 1.5rem;
19
  }
20
  .footer-links {
21
  display: flex;
22
  justify-content: center;
23
  gap: 1.5rem;
24
- flex-wrap: wrap;
25
  }
26
  .footer-links a {
27
- color: #a0aec0;
28
  text-decoration: none;
29
  transition: color 0.2s;
30
  }
31
  .footer-links a:hover {
32
- color: #ffffff;
33
  }
34
  .copyright {
35
- color: #718096;
36
  font-size: 0.875rem;
37
  }
38
  @media (max-width: 640px) {
39
  .footer-links {
40
  flex-direction: column;
41
- gap: 0.75rem;
42
  align-items: center;
 
43
  }
44
  }
45
  </style>
@@ -49,11 +49,9 @@ class CustomFooter extends HTMLElement {
49
  <a href="#">Privacy Policy</a>
50
  <a href="#">Terms of Service</a>
51
  <a href="#">Contact Us</a>
52
- <a href="#">API Documentation</a>
53
- </div>
54
- <div class="copyright">
55
- &copy; ${new Date().getFullYear()} Bulk Order Blaster. All rights reserved.
56
  </div>
 
57
  </div>
58
  </footer>
59
  `;
 
4
  this.shadowRoot.innerHTML = `
5
  <style>
6
  footer {
7
+ background: #1e293b;
8
+ color: white;
9
+ padding: 2rem;
10
  text-align: center;
11
+ margin-top: 2rem;
12
  }
13
  .footer-content {
14
  max-width: 1200px;
15
  margin: 0 auto;
16
  display: flex;
17
  flex-direction: column;
18
+ gap: 1rem;
19
  }
20
  .footer-links {
21
  display: flex;
22
  justify-content: center;
23
  gap: 1.5rem;
24
+ margin-bottom: 1rem;
25
  }
26
  .footer-links a {
27
+ color: #cbd5e1;
28
  text-decoration: none;
29
  transition: color 0.2s;
30
  }
31
  .footer-links a:hover {
32
+ color: white;
33
  }
34
  .copyright {
35
+ color: #94a3b8;
36
  font-size: 0.875rem;
37
  }
38
  @media (max-width: 640px) {
39
  .footer-links {
40
  flex-direction: column;
 
41
  align-items: center;
42
+ gap: 0.5rem;
43
  }
44
  }
45
  </style>
 
49
  <a href="#">Privacy Policy</a>
50
  <a href="#">Terms of Service</a>
51
  <a href="#">Contact Us</a>
52
+ <a href="#">Help Center</a>
 
 
 
53
  </div>
54
+ <p class="copyright">&copy; ${new Date().getFullYear()} BulkOrder Blitz. All rights reserved.</p>
55
  </div>
56
  </footer>
57
  `;
components/navbar.js CHANGED
@@ -4,40 +4,43 @@ class CustomNavbar extends HTMLElement {
4
  this.shadowRoot.innerHTML = `
5
  <style>
6
  nav {
7
- background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%);
8
  padding: 1rem 2rem;
9
  display: flex;
10
  justify-content: space-between;
11
  align-items: center;
12
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
13
  }
14
- .logo {
15
- color: white;
16
- font-weight: bold;
17
  font-size: 1.25rem;
18
  display: flex;
19
  align-items: center;
20
  gap: 0.5rem;
21
  }
22
- ul {
23
- display: flex;
24
- gap: 1.5rem;
25
- list-style: none;
26
- margin: 0;
27
- padding: 0;
28
  }
29
- a {
30
- color: white;
31
- text-decoration: none;
32
- transition: opacity 0.2s;
33
  font-weight: 500;
34
- padding: 0.5rem 0;
35
- border-bottom: 2px solid transparent;
36
- transition: all 0.2s;
 
 
 
 
37
  }
38
- a:hover {
39
- opacity: 0.9;
40
- border-bottom-color: white;
41
  }
42
  @media (max-width: 640px) {
43
  nav {
@@ -52,15 +55,14 @@ class CustomNavbar extends HTMLElement {
52
  }
53
  </style>
54
  <nav>
55
- <div class="logo">
56
- <i data-feather="package"></i>
57
- <span>Bulk Order Blaster</span>
58
- </div>
59
  <ul>
60
- <li><a href="/">Home</a></li>
61
- <li><a href="#">Orders</a></li>
62
- <li><a href="#">Settings</a></li>
63
- <li><a href="#">Help</a></li>
64
  </ul>
65
  </nav>
66
  `;
 
4
  this.shadowRoot.innerHTML = `
5
  <style>
6
  nav {
7
+ background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
8
  padding: 1rem 2rem;
9
  display: flex;
10
  justify-content: space-between;
11
  align-items: center;
12
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
13
  }
14
+ .logo {
15
+ color: white;
16
+ font-weight: 700;
17
  font-size: 1.25rem;
18
  display: flex;
19
  align-items: center;
20
  gap: 0.5rem;
21
  }
22
+ ul {
23
+ display: flex;
24
+ gap: 1.5rem;
25
+ list-style: none;
26
+ margin: 0;
27
+ padding: 0;
28
  }
29
+ a {
30
+ color: white;
31
+ text-decoration: none;
 
32
  font-weight: 500;
33
+ transition: opacity 0.2s;
34
+ display: flex;
35
+ align-items: center;
36
+ gap: 0.3rem;
37
+ }
38
+ a:hover {
39
+ opacity: 0.9;
40
  }
41
+ .nav-icon {
42
+ width: 18px;
43
+ height: 18px;
44
  }
45
  @media (max-width: 640px) {
46
  nav {
 
55
  }
56
  </style>
57
  <nav>
58
+ <a href="/" class="logo">
59
+ <i data-feather="package" class="nav-icon"></i>
60
+ <span>BulkOrder Blitz</span>
61
+ </a>
62
  <ul>
63
+ <li><a href="/"><i data-feather="home" class="nav-icon"></i> Home</a></li>
64
+ <li><a href="/orders.html"><i data-feather="list" class="nav-icon"></i> Orders</a></li>
65
+ <li><a href="/upload.html" class="font-bold"><i data-feather="upload" class="nav-icon"></i> Upload</a></li>
 
66
  </ul>
67
  </nav>
68
  `;
index.html CHANGED
@@ -3,101 +3,105 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Bulk Order Blaster 🚀</title>
7
  <link rel="stylesheet" href="style.css">
8
  <script src="https://cdn.tailwindcss.com"></script>
9
  <script src="https://unpkg.com/feather-icons"></script>
10
  <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
11
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.3/dropzone.min.css">
12
  </head>
13
  <body class="bg-gray-50 min-h-screen">
14
  <custom-navbar></custom-navbar>
15
 
16
  <main class="container mx-auto px-4 py-8">
17
  <div class="max-w-4xl mx-auto bg-white rounded-xl shadow-md overflow-hidden p-6">
18
- <h1 class="text-3xl font-bold text-gray-800 mb-6">Bulk Order Processing</h1>
19
 
20
- <div class="space-y-8">
21
- <!-- Merchant ID Input -->
22
- <div class="space-y-2">
23
- <label for="merchant-id" class="block text-sm font-medium text-gray-700">Merchant ID</label>
24
- <div class="flex items-center">
25
- <i data-feather="user" class="text-gray-500 mr-2"></i>
26
- <input type="text" id="merchant-id" placeholder="Enter your merchant ID"
27
- class="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition">
 
28
  </div>
29
  </div>
30
-
31
- <!-- File Dropzone -->
32
- <div class="space-y-2">
33
- <div class="flex items-center justify-between">
34
- <label class="block text-sm font-medium text-gray-700">Upload Order File</label>
35
- <button id="download-template" class="text-sm text-blue-600 hover:text-blue-800 flex items-center">
36
- <i data-feather="download" class="w-4 h-4 mr-1"></i> Download Template
37
- </button>
38
- </div>
39
- <div id="dropzone" class="border-2 border-dashed border-gray-300 rounded-xl p-8 text-center cursor-pointer hover:border-blue-500 transition">
40
- <div class="flex flex-col items-center justify-center space-y-2">
41
- <i data-feather="upload" class="w-12 h-12 text-gray-400"></i>
42
- <p class="text-gray-500">Drag & drop your order file here or click to browse</p>
43
- <p class="text-xs text-gray-400">Supports: CSV, XLSX (Max 5MB). <span class="text-blue-600 cursor-pointer" id="show-preview">Preview</span></p>
44
- </div>
45
- <input type="file" id="file-input" class="hidden" accept=".csv,.xlsx">
46
- </div>
47
  </div>
48
-
49
- <!-- Data Preview -->
50
- <div class="space-y-2">
51
- <div class="flex items-center justify-between">
52
- <label class="block text-sm font-medium text-gray-700">Order Preview</label>
53
- <button id="refresh-btn" class="text-sm text-blue-500 hover:text-blue-700 flex items-center">
54
- <i data-feather="refresh-cw" class="w-4 h-4 mr-1"></i> Refresh
55
- </button>
56
- </div>
57
- <div id="preview-container" class="hidden bg-gray-50 rounded-lg p-4 min-h-40 border border-gray-200">
58
- <div id="empty-state" class="text-center py-10">
59
- <i data-feather="file-text" class="w-10 h-10 mx-auto text-gray-400"></i>
60
- <p class="mt-2 text-gray-500">No data to preview. Upload a file to see the preview.</p>
61
- </div>
62
- <div id="preview-content" class="overflow-x-auto">
63
- <table class="min-w-full divide-y divide-gray-200">
64
- <thead id="preview-head" class="bg-gray-100">
65
- <!-- Headers will be inserted here -->
66
- </thead>
67
- <tbody id="preview-body" class="bg-white divide-y divide-gray-200">
68
- <!-- Rows will be inserted here -->
69
- </tbody>
70
- </table>
71
- <div id="preview-stats" class="mt-4 text-sm text-gray-500">
72
- <!-- Stats will be inserted here -->
73
- </div>
74
  </div>
75
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  </div>
77
 
78
- <!-- Action Buttons -->
79
- <div class="flex justify-end space-x-4 pt-4">
80
- <button id="clear-btn" class="px-4 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-100 transition">
81
- Clear All
82
  </button>
83
- <button id="process-btn" disabled class="px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition flex items-center disabled:opacity-50 disabled:cursor-not-allowed">
84
- <i data-feather="send" class="w-4 h-4 mr-2"></i> Process Orders
85
  </button>
86
  </div>
87
  </div>
88
  </div>
89
  </main>
90
-
91
  <custom-footer></custom-footer>
92
 
 
 
 
 
 
 
 
93
  <script src="components/navbar.js"></script>
94
  <script src="components/footer.js"></script>
95
- <script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.3/min/dropzone.min.js"></script>
96
- <script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
97
  <script src="script.js"></script>
98
  <script>
99
  feather.replace();
100
  </script>
101
- <script src="https://deepsite.hf.co/deepsite-badge.js"></script>
102
  </body>
103
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Bulk Order Upload</title>
7
  <link rel="stylesheet" href="style.css">
8
  <script src="https://cdn.tailwindcss.com"></script>
9
  <script src="https://unpkg.com/feather-icons"></script>
10
  <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
11
+ <script src="https://cdn.jsdelivr.net/npm/sortablejs@1.14.0/Sortable.min.js"></script>
12
  </head>
13
  <body class="bg-gray-50 min-h-screen">
14
  <custom-navbar></custom-navbar>
15
 
16
  <main class="container mx-auto px-4 py-8">
17
  <div class="max-w-4xl mx-auto bg-white rounded-xl shadow-md overflow-hidden p-6">
18
+ <h1 class="text-3xl font-bold text-gray-800 mb-6">Bulk Order Upload</h1>
19
 
20
+ <!-- Merchant ID Input -->
21
+ <div class="mb-8">
22
+ <label for="merchantId" class="block text-sm font-medium text-gray-700 mb-2">Merchant ID</label>
23
+ <div class="relative rounded-md shadow-sm">
24
+ <input type="text" id="merchantId"
25
+ class="focus:ring-indigo-500 focus:border-indigo-500 block w-full pl-4 pr-12 py-3 sm:text-sm border-gray-300 rounded-md border"
26
+ placeholder="Enter merchant ID">
27
+ <div class="absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none">
28
+ <i data-feather="user" class="text-gray-400"></i>
29
  </div>
30
  </div>
31
+ </div>
32
+
33
+ <!-- Drag & Drop Zone -->
34
+ <div id="dropZone" class="border-2 border-dashed border-gray-300 rounded-lg p-8 text-center mb-8 transition-colors hover:border-indigo-400">
35
+ <div class="flex flex-col items-center justify-center space-y-4">
36
+ <i data-feather="upload-cloud" class="w-12 h-12 text-gray-400"></i>
37
+ <h3 class="text-lg font-medium text-gray-700">Drag & drop your file here</h3>
38
+ <p class="text-sm text-gray-500">or</p>
39
+ <button id="browseBtn" class="px-4 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
40
+ Browse Files
41
+ </button>
42
+ <input type="file" id="fileInput" class="hidden" accept=".csv,.xlsx,.xls">
43
+ <p class="text-xs text-gray-400 mt-2">Supported formats: CSV, XLSX, XLS</p>
 
 
 
 
44
  </div>
45
+ </div>
46
+ <div id="fileInfo" class="hidden mb-8 p-4 bg-gray-50 rounded-lg">
47
+ <div class="flex items-center justify-between">
48
+ <div class="flex items-center space-x-3">
49
+ <i data-feather="file" class="text-indigo-600"></i>
50
+ <div>
51
+ <p id="fileName" class="text-sm font-medium text-gray-700"></p>
52
+ <p id="fileSize" class="text-xs text-gray-500"></p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  </div>
54
  </div>
55
+ <button id="removeFile" class="text-gray-400 hover:text-gray-600">
56
+ <i data-feather="x"></i>
57
+ </button>
58
+ </div>
59
+ </div>
60
+
61
+ <!-- Preview Section -->
62
+ <div id="previewSection" class="hidden">
63
+ <h2 class="text-xl font-semibold text-gray-800 mb-4">Preview</h2>
64
+ <div class="overflow-x-auto bg-gray-50 rounded-lg p-4 mb-6">
65
+ <table id="previewTable" class="min-w-full divide-y divide-gray-200">
66
+ <thead class="bg-gray-100">
67
+ <tr>
68
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Column 1</th>
69
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Column 2</th>
70
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Column 3</th>
71
+ </tr>
72
+ </thead>
73
+ <tbody class="bg-white divide-y divide-gray-200" id="previewBody">
74
+ <!-- Preview data will be inserted here -->
75
+ </tbody>
76
+ </table>
77
  </div>
78
 
79
+ <div class="flex justify-end space-x-3">
80
+ <button id="cancelBtn" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
81
+ Cancel
 
82
  </button>
83
+ <button id="processBtn" class="px-4 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
84
+ Process Orders
85
  </button>
86
  </div>
87
  </div>
88
  </div>
89
  </main>
90
+
91
  <custom-footer></custom-footer>
92
 
93
+ <!-- Toast Notification -->
94
+ <div id="toast" class="fixed bottom-4 right-4 hidden">
95
+ <div class="bg-gray-800 text-white px-4 py-2 rounded-md shadow-lg flex items-center">
96
+ <span id="toastMessage"></span>
97
+ </div>
98
+ </div>
99
+
100
  <script src="components/navbar.js"></script>
101
  <script src="components/footer.js"></script>
 
 
102
  <script src="script.js"></script>
103
  <script>
104
  feather.replace();
105
  </script>
 
106
  </body>
107
  </html>
script.js CHANGED
@@ -1,54 +1,23 @@
1
-
2
  document.addEventListener('DOMContentLoaded', function() {
3
- // DOM Elements
4
- const downloadTemplateBtn = document.getElementById('download-template');
5
- const showPreviewLink = document.getElementById('show-preview');
6
- const dropzone = document.getElementById('dropzone');
7
- const fileInput = document.getElementById('file-input');
8
- const merchantIdInput = document.getElementById('merchant-id');
9
- const previewContainer = document.getElementById('preview-container');
10
- const emptyState = document.getElementById('empty-state');
11
- const previewContent = document.getElementById('preview-content');
12
- const previewHead = document.getElementById('preview-head');
13
- const previewBody = document.getElementById('preview-body');
14
- const previewStats = document.getElementById('preview-stats');
15
- const clearBtn = document.getElementById('clear-btn');
16
- const processBtn = document.getElementById('process-btn');
17
- const refreshBtn = document.getElementById('refresh-btn');
18
- let fileData = null;
19
-
20
- // Download template functionality
21
- downloadTemplateBtn.addEventListener('click', () => {
22
- // Create sample data
23
- const sampleData = [
24
- ['OrderID', 'Customer', 'Product', 'Quantity', 'Price'],
25
- ['ORD001', 'John Doe', 'Product A', '2', '19.99'],
26
- ['ORD002', 'Jane Smith', 'Product B', '1', '29.99'],
27
- ['ORD003', 'Bob Johnson', 'Product C', '3', '9.99']
28
- ];
29
-
30
- // Create workbook
31
- const wb = XLSX.utils.book_new();
32
- const ws = XLSX.utils.aoa_to_sheet(sampleData);
33
- XLSX.utils.book_append_sheet(wb, ws, 'Orders');
34
-
35
- // Generate and download
36
- XLSX.writeFile(wb, 'Order_Template.xlsx');
37
- });
38
-
39
- // Toggle preview visibility
40
- showPreviewLink.addEventListener('click', () => {
41
- if (fileData) {
42
- previewContainer.classList.toggle('hidden');
43
- showPreviewLink.textContent = previewContainer.classList.contains('hidden') ? 'Show Preview' : 'Hide Preview';
44
- } else {
45
- previewContainer.classList.add('hidden');
46
- showPreviewLink.textContent = 'Preview';
47
- }
48
- });
49
- // Drag and drop events
50
  ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
51
- dropzone.addEventListener(eventName, preventDefaults, false);
52
  });
53
 
54
  function preventDefaults(e) {
@@ -57,207 +26,135 @@ const dropzone = document.getElementById('dropzone');
57
  }
58
 
59
  ['dragenter', 'dragover'].forEach(eventName => {
60
- dropzone.addEventListener(eventName, highlight, false);
61
  });
62
 
63
  ['dragleave', 'drop'].forEach(eventName => {
64
- dropzone.addEventListener(eventName, unhighlight, false);
65
  });
66
 
67
  function highlight() {
68
- dropzone.classList.add('bg-blue-50', 'border-blue-500');
69
  }
70
 
71
  function unhighlight() {
72
- dropzone.classList.remove('bg-blue-50', 'border-blue-500');
73
  }
74
 
75
- dropzone.addEventListener('drop', handleDrop, false);
76
- dropzone.addEventListener('click', () => fileInput.click());
77
-
78
- fileInput.addEventListener('change', handleFiles);
79
 
80
  function handleDrop(e) {
81
  const dt = e.dataTransfer;
82
  const files = dt.files;
83
- handleFiles({ target: { files } });
84
  }
85
 
86
- function handleFiles(e) {
87
- const files = e.target.files;
88
- if (files.length) {
89
- processFile(files[0]);
90
- }
91
- }
 
 
92
 
93
- // File processing
94
- function processFile(file) {
95
- if (!['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'text/csv'].includes(file.type) &&
96
- !file.name.endsWith('.xlsx') && !file.name.endsWith('.csv')) {
97
- alert('Please upload a valid CSV or Excel file.');
 
 
 
 
 
 
 
 
 
98
  return;
99
  }
100
 
101
- if (file.size > 5 * 1024 * 1024) {
102
- alert('File size exceeds 5MB limit.');
 
103
  return;
104
  }
105
 
106
- const reader = new FileReader();
107
-
108
- reader.onload = function(e) {
109
- const data = e.target.result;
110
- try {
111
- if (file.name.endsWith('.xlsx')) {
112
- processExcel(data);
113
- } else {
114
- processCSV(data);
115
- }
116
- } catch (error) {
117
- console.error('Error processing file:', error);
118
- alert('Error processing file. Please check the format and try again.');
119
- }
120
- };
121
 
122
- reader.onerror = function() {
123
- alert('Error reading file. Please try again.');
124
- };
125
 
126
- if (file.name.endsWith('.xlsx')) {
127
- reader.readAsArrayBuffer(file);
128
- } else {
129
- reader.readAsText(file);
 
130
  }
 
 
 
 
131
  }
132
 
133
- function processExcel(data) {
134
- const workbook = XLSX.read(data, { type: 'array' });
135
- const firstSheetName = workbook.SheetNames[0];
136
- const worksheet = workbook.Sheets[firstSheetName];
137
- const jsonData = XLSX.utils.sheet_to_json(worksheet);
138
 
139
- if (jsonData.length) {
140
- fileData = jsonData;
141
- showPreview(jsonData);
142
- } else {
143
- alert('No data found in the Excel file.');
144
- }
145
  }
146
 
147
- function processCSV(data) {
148
- const lines = data.split('\n');
149
- const headers = lines[0].split(',');
150
- const result = [];
151
-
152
- for (let i = 1; i < lines.length; i++) {
153
- if (!lines[i]) continue;
154
- const obj = {};
155
- const currentline = lines[i].split(',');
156
-
157
- for (let j = 0; j < headers.length; j++) {
158
- obj[headers[j]] = currentline[j];
159
- }
160
- result.push(obj);
161
- }
162
-
163
- if (result.length) {
164
- fileData = result;
165
- showPreview(result);
166
- } else {
167
- alert('No data found in the CSV file.');
168
- }
169
- }
170
- function showPreview(data) {
171
- emptyState.classList.add('hidden');
172
- previewContainer.classList.remove('hidden');
173
- showPreviewLink.textContent = 'Hide Preview';
174
- // Clear previous preview
175
- previewHead.innerHTML = '';
176
  previewBody.innerHTML = '';
177
 
178
- // Set headers
179
- const headers = Object.keys(data[0]);
180
- const headerRow = document.createElement('tr');
181
-
182
- headers.forEach(header => {
183
- const th = document.createElement('th');
184
- th.textContent = header;
185
- headerRow.appendChild(th);
186
- });
187
-
188
- previewHead.appendChild(headerRow);
189
-
190
- // Set rows (limit to 10 for preview)
191
- const previewRows = data.slice(0, 10);
192
-
193
- previewRows.forEach(row => {
194
- const tr = document.createElement('tr');
195
-
196
- headers.forEach(header => {
197
- const td = document.createElement('td');
198
- td.textContent = row[header] || 'N/A';
199
- tr.appendChild(td);
200
- });
201
-
202
- previewBody.appendChild(tr);
203
- });
204
-
205
- // Set stats
206
- previewStats.innerHTML = `
207
- Showing ${previewRows.length} of ${data.length} rows.
208
- ${data.length > 10 ? 'Only first 10 rows are shown in preview.' : ''}
209
- `;
210
-
211
- // Enable process button if merchant ID is filled
212
- updateProcessButton();
213
- }
214
- function updateProcessButton() {
215
- processBtn.disabled = !(fileData && merchantIdInput.value.trim());
216
- if (!fileData) {
217
- previewContainer.classList.add('hidden');
218
- showPreviewLink.textContent = 'Preview';
219
  }
 
 
220
  }
221
- merchantIdInput.addEventListener('input', updateProcessButton);
222
 
223
- // Button actions
224
- clearBtn.addEventListener('click', () => {
225
  fileInput.value = '';
226
- fileData = null;
227
- emptyState.classList.remove('hidden');
228
- previewContent.classList.add('hidden');
229
- previewContainer.classList.add('hidden');
230
- merchantIdInput.value = '';
231
- processBtn.disabled = true;
232
- showPreviewLink.textContent = 'Preview';
233
- });
234
- refreshBtn.addEventListener('click', () => {
235
- if (fileData) {
236
- showPreview(fileData);
237
- }
238
- });
239
 
240
- processBtn.addEventListener('click', () => {
241
- if (!merchantIdInput.value.trim()) {
242
- alert('Please enter a merchant ID.');
243
- return;
244
- }
245
-
246
- if (!fileData) {
247
- alert('Please upload a file first.');
248
- return;
249
- }
250
-
251
- // Simulate processing
252
- processBtn.disabled = true;
253
- processBtn.innerHTML = '<i data-feather="loader" class="w-4 h-4 mr-2 animate-spin"></i> Processing...';
254
- feather.replace();
255
 
256
  setTimeout(() => {
257
- alert(`Success! Processed ${fileData.length} orders for merchant ${merchantIdInput.value.trim()}.`);
258
- processBtn.disabled = false;
259
- processBtn.innerHTML = '<i data-feather="send" class="w-4 h-4 mr-2"></i> Process Orders';
260
- feather.replace();
261
- }, 2000);
262
- });
263
  });
 
 
1
  document.addEventListener('DOMContentLoaded', function() {
2
+ const dropZone = document.getElementById('dropZone');
3
+ const fileInput = document.getElementById('fileInput');
4
+ const browseBtn = document.getElementById('browseBtn');
5
+ const fileInfo = document.getElementById('fileInfo');
6
+ const fileName = document.getElementById('fileName');
7
+ const fileSize = document.getElementById('fileSize');
8
+ const removeFile = document.getElementById('removeFile');
9
+ const previewSection = document.getElementById('previewSection');
10
+ const previewBody = document.getElementById('previewBody');
11
+ const cancelBtn = document.getElementById('cancelBtn');
12
+ const processBtn = document.getElementById('processBtn');
13
+ const toast = document.getElementById('toast');
14
+ const toastMessage = document.getElementById('toastMessage');
15
+
16
+ let selectedFile = null;
17
+
18
+ // Handle drag and drop events
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
20
+ dropZone.addEventListener(eventName, preventDefaults, false);
21
  });
22
 
23
  function preventDefaults(e) {
 
26
  }
27
 
28
  ['dragenter', 'dragover'].forEach(eventName => {
29
+ dropZone.addEventListener(eventName, highlight, false);
30
  });
31
 
32
  ['dragleave', 'drop'].forEach(eventName => {
33
+ dropZone.addEventListener(eventName, unhighlight, false);
34
  });
35
 
36
  function highlight() {
37
+ dropZone.classList.add('highlight');
38
  }
39
 
40
  function unhighlight() {
41
+ dropZone.classList.remove('highlight');
42
  }
43
 
44
+ // Handle dropped files
45
+ dropZone.addEventListener('drop', handleDrop, false);
 
 
46
 
47
  function handleDrop(e) {
48
  const dt = e.dataTransfer;
49
  const files = dt.files;
50
+ handleFiles(files);
51
  }
52
 
53
+ // Browse files button
54
+ browseBtn.addEventListener('click', () => {
55
+ fileInput.click();
56
+ });
57
+
58
+ fileInput.addEventListener('change', function() {
59
+ handleFiles(this.files);
60
+ });
61
 
62
+ // Remove file button
63
+ removeFile.addEventListener('click', function() {
64
+ resetFileUpload();
65
+ });
66
+
67
+ // Cancel button
68
+ cancelBtn.addEventListener('click', function() {
69
+ resetFileUpload();
70
+ });
71
+
72
+ // Process button
73
+ processBtn.addEventListener('click', function() {
74
+ if (!selectedFile) {
75
+ showToast('Please upload a file first', 'error');
76
  return;
77
  }
78
 
79
+ const merchantId = document.getElementById('merchantId').value;
80
+ if (!merchantId) {
81
+ showToast('Please enter a merchant ID', 'error');
82
  return;
83
  }
84
 
85
+ // Simulate processing
86
+ showToast('Processing bulk orders...', 'success');
87
+ setTimeout(() => {
88
+ showToast('Bulk orders processed successfully!', 'success');
89
+ resetFileUpload();
90
+ }, 2000);
91
+ });
92
+
93
+ function handleFiles(files) {
94
+ if (files.length === 0) return;
 
 
 
 
 
95
 
96
+ const file = files[0];
97
+ const validTypes = ['text/csv', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'];
 
98
 
99
+ if (!validTypes.includes(file.type) && !file.name.match(/\.(csv|xlsx|xls)$/i)) {
100
+ showToast('Invalid file type. Please upload a CSV or Excel file.', 'error');
101
+ dropZone.classList.add('error');
102
+ setTimeout(() => dropZone.classList.remove('error'), 2000);
103
+ return;
104
  }
105
+
106
+ selectedFile = file;
107
+ displayFileInfo(file);
108
+ showPreview();
109
  }
110
 
111
+ function displayFileInfo(file) {
112
+ fileName.textContent = file.name;
 
 
 
113
 
114
+ // Format file size
115
+ const sizeInMB = (file.size / (1024 * 1024)).toFixed(2);
116
+ fileSize.textContent = `${sizeInMB} MB`;
117
+
118
+ fileInfo.classList.remove('hidden');
119
+ dropZone.classList.add('hidden');
120
  }
121
 
122
+ function showPreview() {
123
+ // In a real app, you would parse the file and display actual data
124
+ // For demo purposes, we'll show mock data
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  previewBody.innerHTML = '';
126
 
127
+ // Add mock rows
128
+ for (let i = 0; i < 5; i++) {
129
+ const row = document.createElement('tr');
130
+ row.innerHTML = `
131
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">Product ${i+1}</td>
132
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${Math.floor(Math.random() * 10) + 1}</td>
133
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$${(Math.random() * 100).toFixed(2)}</td>
134
+ `;
135
+ previewBody.appendChild(row);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  }
137
+
138
+ previewSection.classList.remove('hidden');
139
  }
 
140
 
141
+ function resetFileUpload() {
142
+ selectedFile = null;
143
  fileInput.value = '';
144
+ fileInfo.classList.add('hidden');
145
+ previewSection.classList.add('hidden');
146
+ dropZone.classList.remove('hidden');
147
+ }
 
 
 
 
 
 
 
 
 
148
 
149
+ function showToast(message, type = 'success') {
150
+ toastMessage.textContent = message;
151
+ toast.className = `fixed bottom-4 right-4 flex items-center ${type === 'success' ? 'toast-success' : 'toast-error'} px-4 py-2 rounded-md shadow-lg`;
152
+ toast.classList.add('show');
 
 
 
 
 
 
 
 
 
 
 
153
 
154
  setTimeout(() => {
155
+ toast.classList.remove('show');
156
+ toast.classList.add('hide');
157
+ setTimeout(() => toast.classList.add('hidden'), 300);
158
+ }, 3000);
159
+ }
 
160
  });
style.css CHANGED
@@ -1,51 +1,41 @@
1
  /* Shared styles across all pages */
2
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
3
-
4
  body {
5
- font-family: 'Inter', sans-serif;
6
- display: flex;
7
- flex-direction: column;
8
- min-height: 100vh;
9
  }
10
 
11
- #dropzone {
12
- transition: all 0.3s ease;
 
13
  }
14
 
15
- #dropzone.active {
16
- border-color: #3b82f6;
17
- background-color: #f0f7ff;
18
- }
19
- #preview-container {
20
- transition: all 0.3s ease;
21
  }
22
 
23
- #download-template {
24
- transition: all 0.2s ease;
25
  }
26
 
27
- #show-preview {
28
- transition: all 0.2s ease;
29
  }
30
- #preview-content table {
31
- font-size: 0.875rem;
 
 
 
32
  }
33
 
34
- #preview-content th {
35
- text-align: left;
36
- padding: 0.5rem 1rem;
37
- font-weight: 500;
38
- text-transform: uppercase;
39
- font-size: 0.75rem;
40
- letter-spacing: 0.05em;
41
- color: #4b5563;
42
  }
43
 
44
- #preview-content td {
45
- padding: 0.75rem 1rem;
46
- white-space: nowrap;
47
  }
48
 
49
- #preview-content tr:nth-child(even) {
50
- background-color: #f9fafb;
51
  }
 
1
  /* Shared styles across all pages */
 
 
2
  body {
3
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
 
 
 
4
  }
5
 
6
+ #dropZone.highlight {
7
+ border-color: #818cf8;
8
+ background-color: #f5f3ff;
9
  }
10
 
11
+ #dropZone.error {
12
+ border-color: #ef4444;
13
+ background-color: #fee2e2;
 
 
 
14
  }
15
 
16
+ .toast-success {
17
+ background-color: #10b981 !important;
18
  }
19
 
20
+ .toast-error {
21
+ background-color: #ef4444 !important;
22
  }
23
+
24
+ /* Animation for toast */
25
+ @keyframes slideIn {
26
+ from { transform: translateX(100%); opacity: 0; }
27
+ to { transform: translateX(0); opacity: 1; }
28
  }
29
 
30
+ @keyframes slideOut {
31
+ from { transform: translateX(0); opacity: 1; }
32
+ to { transform: translateX(100%); opacity: 0; }
 
 
 
 
 
33
  }
34
 
35
+ #toast.show {
36
+ animation: slideIn 0.3s forwards;
 
37
  }
38
 
39
+ #toast.hide {
40
+ animation: slideOut 0.3s forwards;
41
  }