stat2025 commited on
Commit
e3af61a
·
verified ·
1 Parent(s): 04f004a

Delete app.js

Browse files
Files changed (1) hide show
  1. app.js +0 -364
app.js DELETED
@@ -1,364 +0,0 @@
1
- /* =========
2
- Storage
3
- ========= */
4
- const STORAGE_KEY = "eq_receipts_v1";
5
-
6
- function loadRows() {
7
- try {
8
- const raw = localStorage.getItem(STORAGE_KEY);
9
- return raw ? JSON.parse(raw) : [];
10
- } catch {
11
- return [];
12
- }
13
- }
14
-
15
- function saveRows(rows) {
16
- localStorage.setItem(STORAGE_KEY, JSON.stringify(rows));
17
- }
18
-
19
- /* =========
20
- Helpers
21
- ========= */
22
- function uid() {
23
- return Math.random().toString(16).slice(2) + Date.now().toString(16);
24
- }
25
-
26
- function nowLabel() {
27
- const d = new Date();
28
- return d.toLocaleString("ar-SA");
29
- }
30
-
31
- function setDefaultDate() {
32
- const d = new Date();
33
- const yyyy = d.getFullYear();
34
- const mm = String(d.getMonth() + 1).padStart(2, "0");
35
- const dd = String(d.getDate()).padStart(2, "0");
36
- document.getElementById("date").value = `${yyyy}-${mm}-${dd}`;
37
- }
38
-
39
- function sanitizePhone(v) {
40
- return (v || "").replace(/[^\d+]/g, "").trim();
41
- }
42
-
43
- /* =========
44
- Signature Canvas (draw)
45
- ========= */
46
- const canvas = document.getElementById("sigCanvas");
47
- const ctx = canvas.getContext("2d");
48
-
49
- let drawing = false;
50
- let last = { x: 0, y: 0 };
51
-
52
- function getCanvasPoint(e) {
53
- const rect = canvas.getBoundingClientRect();
54
- const clientX = e.touches ? e.touches[0].clientX : e.clientX;
55
- const clientY = e.touches ? e.touches[0].clientY : e.clientY;
56
- return {
57
- x: (clientX - rect.left) * (canvas.width / rect.width),
58
- y: (clientY - rect.top) * (canvas.height / rect.height),
59
- };
60
- }
61
-
62
- function startDraw(e) {
63
- drawing = true;
64
- last = getCanvasPoint(e);
65
- e.preventDefault();
66
- }
67
-
68
- function moveDraw(e) {
69
- if (!drawing) return;
70
- const p = getCanvasPoint(e);
71
-
72
- ctx.lineWidth = 3;
73
- ctx.lineCap = "round";
74
- ctx.lineJoin = "round";
75
- ctx.strokeStyle = "#0f172a";
76
-
77
- ctx.beginPath();
78
- ctx.moveTo(last.x, last.y);
79
- ctx.lineTo(p.x, p.y);
80
- ctx.stroke();
81
-
82
- last = p;
83
- e.preventDefault();
84
- }
85
-
86
- function endDraw() {
87
- drawing = false;
88
- }
89
-
90
- function clearSignature() {
91
- ctx.clearRect(0, 0, canvas.width, canvas.height);
92
- }
93
-
94
- function signatureDataURL() {
95
- // if empty => return ""
96
- const blank = document.createElement("canvas");
97
- blank.width = canvas.width;
98
- blank.height = canvas.height;
99
- if (canvas.toDataURL() === blank.toDataURL()) return "";
100
- return canvas.toDataURL("image/png");
101
- }
102
-
103
- canvas.addEventListener("mousedown", startDraw);
104
- canvas.addEventListener("mousemove", moveDraw);
105
- window.addEventListener("mouseup", endDraw);
106
-
107
- canvas.addEventListener("touchstart", startDraw, { passive: false });
108
- canvas.addEventListener("touchmove", moveDraw, { passive: false });
109
- canvas.addEventListener("touchend", endDraw);
110
-
111
- document.getElementById("clearSigBtn").addEventListener("click", clearSignature);
112
-
113
- /* =========
114
- UI Elements
115
- ========= */
116
- const form = document.getElementById("entryForm");
117
- const editIdEl = document.getElementById("editId");
118
- const rowsCountEl = document.getElementById("rowsCount");
119
- const lastSavedEl = document.getElementById("lastSaved");
120
- const tableBody = document.getElementById("tableBody");
121
- const searchEl = document.getElementById("search");
122
-
123
- const inputs = {
124
- companyName: document.getElementById("companyName"),
125
- crNumber: document.getElementById("crNumber"),
126
- receiverName: document.getElementById("receiverName"),
127
- mobile: document.getElementById("mobile"),
128
- email: document.getElementById("email"),
129
- date: document.getElementById("date"),
130
- signatureText: document.getElementById("signatureText"),
131
- };
132
-
133
- let rows = loadRows();
134
-
135
- /* =========
136
- Render
137
- ========= */
138
- function matchesSearch(row, q) {
139
- if (!q) return true;
140
- const hay = [
141
- row.companyName,
142
- row.crNumber,
143
- row.receiverName,
144
- row.mobile,
145
- row.email,
146
- row.date,
147
- ].join(" ").toLowerCase();
148
- return hay.includes(q.toLowerCase());
149
- }
150
-
151
- function render() {
152
- const q = (searchEl.value || "").trim();
153
- const filtered = rows.filter(r => matchesSearch(r, q));
154
-
155
- tableBody.innerHTML = "";
156
-
157
- filtered.forEach((r, idx) => {
158
- const tr = document.createElement("tr");
159
-
160
- const sigCell = (() => {
161
- if (r.signatureText) return escapeHtml(r.signatureText);
162
- if (r.signaturePng) return `<img src="${r.signaturePng}" alt="توقيع" style="height:36px; max-width:120px; object-fit:contain;"/>`;
163
- return `<span style="color:#94a3b8">—</span>`;
164
- })();
165
-
166
- tr.innerHTML = `
167
- <td class="col-n">${idx + 1}</td>
168
- <td>${escapeHtml(r.companyName)}</td>
169
- <td>${escapeHtml(r.crNumber)}</td>
170
- <td>${escapeHtml(r.receiverName)}</td>
171
- <td>${escapeHtml(r.mobile)}</td>
172
- <td>${escapeHtml(r.email || "")}</td>
173
- <td>${escapeHtml(r.date)}</td>
174
- <td>${sigCell}</td>
175
- <td class="col-actions">
176
- <div class="row-actions">
177
- <button class="btn btn-ghost" data-act="edit" data-id="${r.id}">تعديل</button>
178
- <button class="btn btn-danger" data-act="delete" data-id="${r.id}">حذف</button>
179
- </div>
180
- </td>
181
- `;
182
- tableBody.appendChild(tr);
183
- });
184
-
185
- rowsCountEl.textContent = rows.length.toString();
186
- }
187
-
188
- function escapeHtml(str) {
189
- return (str || "")
190
- .replaceAll("&", "&amp;")
191
- .replaceAll("<", "&lt;")
192
- .replaceAll(">", "&gt;")
193
- .replaceAll('"', "&quot;")
194
- .replaceAll("'", "&#039;");
195
- }
196
-
197
- /* =========
198
- Form Actions
199
- ========= */
200
- function resetForm() {
201
- editIdEl.value = "";
202
- inputs.companyName.value = "";
203
- inputs.crNumber.value = "";
204
- inputs.receiverName.value = "";
205
- inputs.mobile.value = "";
206
- inputs.email.value = "";
207
- setDefaultDate();
208
- inputs.signatureText.value = "";
209
- clearSignature();
210
- document.getElementById("saveBtn").textContent = "حفظ";
211
- }
212
-
213
- document.getElementById("resetBtn").addEventListener("click", resetForm);
214
-
215
- form.addEventListener("submit", (e) => {
216
- e.preventDefault();
217
-
218
- const payload = {
219
- companyName: inputs.companyName.value.trim(),
220
- crNumber: inputs.crNumber.value.trim(),
221
- receiverName: inputs.receiverName.value.trim(),
222
- mobile: sanitizePhone(inputs.mobile.value),
223
- email: inputs.email.value.trim(),
224
- date: inputs.date.value,
225
- signatureText: inputs.signatureText.value.trim(),
226
- signaturePng: "",
227
- };
228
-
229
- // if no signatureText, use canvas signature if any
230
- if (!payload.signatureText) {
231
- payload.signaturePng = signatureDataURL();
232
- }
233
-
234
- // Basic validation
235
- if (!payload.companyName || !payload.crNumber || !payload.receiverName || !payload.mobile || !payload.date) {
236
- alert("فضلاً أكمل الحقول المطلوبة.");
237
- return;
238
- }
239
-
240
- const editingId = editIdEl.value;
241
- if (editingId) {
242
- const i = rows.findIndex(r => r.id === editingId);
243
- if (i >= 0) {
244
- rows[i] = { ...rows[i], ...payload };
245
- }
246
- } else {
247
- rows.unshift({ id: uid(), createdAt: Date.now(), ...payload });
248
- }
249
-
250
- saveRows(rows);
251
- lastSavedEl.textContent = nowLabel();
252
- render();
253
- resetForm();
254
- });
255
-
256
- /* =========
257
- Row Buttons
258
- ========= */
259
- tableBody.addEventListener("click", (e) => {
260
- const btn = e.target.closest("button");
261
- if (!btn) return;
262
-
263
- const act = btn.getAttribute("data-act");
264
- const id = btn.getAttribute("data-id");
265
-
266
- if (act === "delete") {
267
- const ok = confirm("هل تريد حذف هذا السجل؟");
268
- if (!ok) return;
269
- rows = rows.filter(r => r.id !== id);
270
- saveRows(rows);
271
- lastSavedEl.textContent = nowLabel();
272
- render();
273
- }
274
-
275
- if (act === "edit") {
276
- const r = rows.find(x => x.id === id);
277
- if (!r) return;
278
-
279
- editIdEl.value = r.id;
280
- inputs.companyName.value = r.companyName || "";
281
- inputs.crNumber.value = r.crNumber || "";
282
- inputs.receiverName.value = r.receiverName || "";
283
- inputs.mobile.value = r.mobile || "";
284
- inputs.email.value = r.email || "";
285
- inputs.date.value = r.date || "";
286
- inputs.signatureText.value = r.signatureText || "";
287
-
288
- clearSignature();
289
- if (r.signaturePng && !r.signatureText) {
290
- const img = new Image();
291
- img.onload = () => ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
292
- img.src = r.signaturePng;
293
- }
294
-
295
- document.getElementById("saveBtn").textContent = "تحديث";
296
- window.scrollTo({ top: 0, behavior: "smooth" });
297
- }
298
- });
299
-
300
- /* =========
301
- Search
302
- ========= */
303
- searchEl.addEventListener("input", render);
304
-
305
- /* =========
306
- Delete All
307
- ========= */
308
- document.getElementById("deleteAllBtn").addEventListener("click", () => {
309
- if (!rows.length) return alert("لا توجد سجلات للحذف.");
310
- const ok = confirm("سيتم حذف جميع السجلات نهائيًا من هذا الجهاز. هل أنت متأكد؟");
311
- if (!ok) return;
312
- rows = [];
313
- saveRows(rows);
314
- lastSavedEl.textContent = nowLabel();
315
- render();
316
- resetForm();
317
- });
318
-
319
- /* =========
320
- Export Excel
321
- ========= */
322
- document.getElementById("exportBtn").addEventListener("click", () => {
323
- if (!rows.length) return alert("لا توجد بيانات لتصديرها.");
324
-
325
- // Prepare Excel rows (match your statement columns)
326
- const data = rows.slice().reverse().map((r, idx) => ({
327
- "م": idx + 1,
328
- "اسم الشركة": r.companyName,
329
- "السجل التجاري": r.crNumber,
330
- "اسم المستلم": r.receiverName,
331
- "رقم الجوال": r.mobile,
332
- "البريد الإلكتروني": r.email || "",
333
- "التاريخ": r.date,
334
- "التوقيع": r.signatureText ? r.signatureText : (r.signaturePng ? "توقيع مرسوم" : ""),
335
- }));
336
-
337
- const ws = XLSX.utils.json_to_sheet(data);
338
- const wb = XLSX.utils.book_new();
339
- XLSX.utils.book_append_sheet(wb, ws, "بيان الاستلام");
340
-
341
- // Auto column widths
342
- const colWidths = [
343
- { wch: 4 }, { wch: 28 }, { wch: 18 }, { wch: 18 },
344
- { wch: 14 }, { wch: 24 }, { wch: 12 }, { wch: 14 }
345
- ];
346
- ws["!cols"] = colWidths;
347
-
348
- const d = new Date();
349
- const yyyy = d.getFullYear();
350
- const mm = String(d.getMonth() + 1).padStart(2, "0");
351
- const dd = String(d.getDate()).padStart(2, "0");
352
- const filename = `بيان_استلام_${yyyy}-${mm}-${dd}.xlsx`;
353
-
354
- XLSX.writeFile(wb, filename);
355
- });
356
-
357
- /* =========
358
- Init
359
- ========= */
360
- (function init() {
361
- setDefaultDate();
362
- lastSavedEl.textContent = "—";
363
- render();
364
- })();