`); win.document.close(); win.focus(); win.print(); }; const handlePrintID = () => { const node = printIDRef.current; if (!node) return; const html = node.outerHTML; const size = designID.orientation === "portrait" ? `${CARD.H}mm ${CARD.W}mm` : `${CARD.W}mm ${CARD.H}mm`; const win = window.open("", "_blank"); win.document.write(`ID Card${html}`); win.document.close(); win.focus(); win.print(); }; const openCertificate = (c) => { const trainee = getTrainee(c.traineeId); const trainer = getTrainer(c.trainerId); const course = getCourse(c.courseId); const html = ` Certificate
Dayim Training Center Under the supervision of the
Technical and Vocational Training Corporation Award this

${trainee?.nameEn || trainee?.nameAr || ""}

For Having Successfully Completed the Training Course of

${course?.titleEn || course?.titleAr || ""}

Trainer: ${trainer?.nameEn || trainer?.nameAr || ""}
Issue Date: ${c.issuedOn}    |    Expiry Date: ${c.expiresOn}
${c.serial}
`; // ✅ OPEN WINDOW const win = window.open("", "_blank"); // ✅ WRITE HTML win.document.write(html); win.document.close(); // ✅ PUT QR CODE GENERATION HERE (IMPORTANT) win.onload = function () { const qrElement = win.document.getElementById("qrcode"); new QRCode(qrElement, { text: `https://dayimrentals.com/api/fetch_qrdata.php?id=${c.id}`, width: 120, height: 120 }); }; }; return (
Issue Certificate
Search in list, choose trainee, trainer & course
setCertForm({ ...certForm, traineeId: id })} options={trainees} getLabel={(t) => (t.nameEn || t.nameAr || "") + (t.idNumber ? ` • ${t.idNumber}` : "")} /> setCertForm({ ...certForm, trainerId: id })} options={trainers} getLabel={(t) => (t.nameEn || t.nameAr || "")} /> setCertForm({ ...certForm, courseId: id })} options={courses} getLabel={(c) => ((c.titleEn || c.titleAr || "") + (c.code ? ` (${c.code})` : ""))} />
Issued On
setCertForm({ ...certForm, issuedOn: e.target.value })} />
Expires On
setCertForm({ ...certForm, expiresOn: e.target.value })} />
Verifier Hint
setCertForm({ ...certForm, verifierHint: e.target.value })} placeholder="e.g., Training Dept. contact" />
Certificates
{certs.map(c => { const t = getTrainee(c.traineeId); const tr = getTrainer(c.trainerId); const crs = getCourse(c.courseId); const expired = isPast(c.expiresOn); return ( ); })} {certs.length === 0 &&}
SerialTraineeCourseTrainerIssuedExpiresStatus
{c.serial}{t?.nameEn || t?.nameAr} {crs?.iconDataUrl && } {crs?.titleEn || crs?.titleAr} ({crs?.code}){tr?.nameEn || tr?.nameAr}{c.issuedOn}{c.expiresOn}{expired ? Expired : Valid}
No certificates.
{previewCert && (
Certificate (A4) Preview
ID Card Preview
)}
); } /* ========== Validate Tab ========== */ function ValidateTab({ certs, getTrainee, getCourse, getTrainer }) { const [code, setCode] = useState(""); const [res, setRes] = useState(null); const validate = () => { const found = certs.find(c => c.id === code || c.serial === code); if (!found) { setRes({ ok: false }); } else { setRes({ ok: true, cert: found, trainee: getTrainee(found.traineeId), course: getCourse(found.courseId), trainer: getTrainer(found.trainerId), }); } }; return (
Validate Certificate
Enter Serial/ID
setCode(e.target.value)} placeholder="Paste Serial (e.g., DAYIM-...)" />
{!res &&
No validation performed yet.
} {res && !res.ok &&
Not found.
} {res && res.ok && (
{isPast(res.cert.expiresOn) ? "Expired" : "Valid"} Serial: {res.cert.serial}
Trainee: {(res.trainee?.nameEn || res.trainee?.nameAr)}
Course: {(res.course?.titleEn || res.course?.titleAr)} ({res.course?.code})
Trainer: {(res.trainer?.nameEn || res.trainer?.nameAr) || "-"}
Issued: {res.cert.issuedOn}
Expires: {res.cert.expiresOn}
)}
); } /* ========== Import / Export Tab ========== */ function ImportExportTab({ onImport, onExport }) { return (
Import / Export
Import your old database (JSON) or export current.
); } /* ========== A4 Designer ========== */ function A4Designer({ design, setDesign, logo, setLogo, saveDesignToWP }) { const canvasW = design.orientation === "portrait" ? 210 * mmToPx : 297 * mmToPx; const canvasH = design.orientation === "portrait" ? 297 * mmToPx : 210 * mmToPx; const update = (path, value) => { const d = structuredClone(design); const parts = path.split("."); let ref = d; for (let i = 0; i < parts.length - 1; i++) ref = ref[parts[i]]; ref[parts[parts.length - 1]] = value; setDesign(d); }; const handleSave = () => { saveDesignToWP(design, null, logo); }; const setFieldPos = (key, nx, ny) => { setDesign(d => { const dd = structuredClone(d); dd.fields[key].x = Math.round(nx); dd.fields[key].y = Math.round(ny); return dd; }); }; const setLogoPos = (nx, ny) => setDesign(d => { const dd = structuredClone(d); dd.logo.x = Math.round(nx); dd.logo.y = Math.round(ny); return dd; }); const setPhotoPos = (nx, ny) => setDesign(d => { const dd = structuredClone(d); dd.photo.x = Math.round(nx); dd.photo.y = Math.round(ny); return dd; }); return (
Orientation
Font Family
update("textFont", e.target.value)} />
Background
update("bgColor", e.target.value)} />
Border
update("borderColor", e.target.value)} />
Upload Logo
{ const f = e.target.files?.[0]; if (!f) return; const r = new FileReader(); r.onload = () => { setLogo(String(r.result)); saveDesignToWP(design, null, String(r.result)); }; r.readAsDataURL(f); }} />
Upload Template
{ const f = e.target.files?.[0]; if (!f) return; const r = new FileReader(); r.onload = () => { update("bgTemplateDataUrl", String(r.result)); }; r.readAsDataURL(f); }} />
{design.bgTemplateDataUrl && ( Template )} {design.watermark && ( wm )} {Object.entries(design.fields).map(([k, f]) => ( setFieldPos(k, nx, ny)}>
{f.text}
))} {"photo" in design && design.photo.show && (
Photo
)} {design.showLogo && (design.logoDataUrl || logo) && ( Logo )}
); } /* ========== ID Designer ========== */ function IDDesigner({ design, setDesign, logo, setLogo, saveDesignToWP }) { const cardWmm = design.orientation === "portrait" ? CARD.H : CARD.W; const cardHmm = design.orientation === "portrait" ? CARD.W : CARD.H; const canvasW = Math.round(cardWmm * mmToPx); const canvasH = Math.round(cardHmm * mmToPx); const update = (path, value) => { const d = structuredClone(design); const parts = path.split("."); let ref = d; for (let i = 0; i < parts.length - 1; i++) ref = ref[parts[i]]; ref[parts[parts.length - 1]] = value; setDesign(d); }; const save = () => { saveDesignToWP(null, design, logo); }; const mmX = (mm) => Math.round(mm * mmToPx); const pxToMm = (px) => +(px / mmToPx).toFixed(2); const setFieldPos = (key, nx, ny) => { setDesign(d => { const dd = structuredClone(d); dd.fields[key].x = pxToMm(nx); dd.fields[key].y = pxToMm(ny); return dd; }); }; const setLogoPos = (nx, ny) => setDesign(d => { const dd = structuredClone(d); dd.logo.x = pxToMm(nx); dd.logo.y = pxToMm(ny); return dd; }); const setPhotoPos = (nx, ny) => setDesign(d => { const dd = structuredClone(d); dd.photo.x = pxToMm(nx); dd.photo.y = pxToMm(ny); return dd; }); return (
Orientation
Background
update("bgColor", e.target.value)} />
Upload Logo
{ const f = e.target.files?.[0]; if (!f) return; const r = new FileReader(); r.onload = () => { setLogo(String(r.result)); saveDesignToWP(null, design, String(r.result)); }; r.readAsDataURL(f); }} />
Upload Template
{ const f = e.target.files?.[0]; if (!f) return; const r = new FileReader(); r.onload = () => { update("bgTemplateDataUrl", String(r.result)); }; r.readAsDataURL(f); }} />
{design.bgTemplateDataUrl && ( Template )} {design.watermark && ( wm )} {Object.entries(design.fields).map(([k, f]) => { const left = mmX(f.x), top = mmX(f.y), fontSizePx = Math.max(8, f.size / 3.78); return ( setFieldPos(k, nx, ny)}>
{f.text}
); })} {"photo" in design && design.photo.show && (
Photo
)} {design.showLogo && (design.logoDataUrl || logo) && ( Logo )}
); } /* ========== Draggable Helper ========== */ function Draggable({ left, top, children, onMove, maxW, maxH }) { const ref = useRef(null); useEffect(() => { const down = (e) => { e.preventDefault(); const startX = e.clientX; const startY = e.clientY; const initX = left; const initY = top; const move = (ev) => { const dx = ev.clientX - startX; const dy = ev.clientY - startY; let nx = initX + dx; let ny = initY + dy; if (nx < 0) nx = 0; if (ny < 0) ny = 0; if (nx > maxW) nx = maxW; if (ny > maxH) ny = maxH; onMove(nx, ny); }; const up = () => { window.removeEventListener("mousemove", move); window.removeEventListener("mouseup", up); }; window.addEventListener("mousemove", move); window.addEventListener("mouseup", up); }; const node = ref.current; if (node) node.addEventListener("mousedown", down); return () => { if (node) node.removeEventListener("mousedown", down); }; }, [left, top, onMove, maxW, maxH]); return (
{children}
); } /* ========== Certificate A4 (no QR) ========== */ function CertificateA4({ design, cert, trainee, course, trainer, logo }) { if (!cert || !trainee || !course) { return
Issue a certificate to preview.
; } const d = design || DEFAULT_DESIGN_A4; const boxStyle = { width: d.orientation === "portrait" ? "210mm" : "297mm", height: d.orientation === "portrait" ? "297mm" : "210mm", background: d.bgColor, border: `1mm solid ${d.borderColor}`, position: "relative", borderRadius: "3mm", fontFamily: d.textFont, overflow: "hidden", }; const fields = d.fields || {}; // English course line instead of Arabic const courseField = fields.courseEn || fields.notesAr || { x: 60, y: 150, size: 22, color: "#111827", weight: 500, text: "for successfully completing the course {courseEn}", }; return (
{d.bgTemplateDataUrl && ( Template )} {d.watermark && ( wm )} {/* Title (EN) */} {fields.titleEn && (
{fields.titleEn.text}
)} {/* Main line: awarded to NAME (EN) */} {fields.notesEn && (
{fields.notesEn.text .replace("{nameEn}", trainee.nameEn || "") .replace("{courseEn}", course.titleEn || "")}
)} {/* English course line */}
{courseField.text.replace("{courseEn}", course.titleEn || "")}
{/* Dates */} {fields.dates && (
Issued: {cert.issuedOn} • Expires: {cert.expiresOn}
)} {/* Serial */} {fields.serial && (
Serial: {cert.serial}
)} {/* Photo */} {"photo" in d && d.photo.show && trainee.photoDataUrl && ( Photo )} {/* Logo */} {d.showLogo && (d.logoDataUrl || logo) && ( Logo )}
); } /* ========== ID Card (English only, with ID Number, no QR) ========== */ function IDCard({ design, cert, trainee, course, trainer, logo }) { if (!cert || !trainee || !course) return
Issue a certificate to preview.
; const mm = (v) => `${v}mm`; const boxStyle = { width: design.orientation === "portrait" ? `${CARD.H}mm` : `${CARD.W}mm`, height: design.orientation === "portrait" ? `${CARD.W}mm` : `${CARD.H}mm`, background: design.bgColor, border: `0.6mm solid ${design.borderColor}`, position: "relative", borderRadius: "2mm", fontFamily: design.textFont, overflow: "hidden", }; return (
{design.bgTemplateDataUrl && ( Template )} {design.watermark && ( wm )} {/* Title EN only */}
{design.fields.titleEn.text}
{/* Name (English only, fallback to Arabic if EN missing) */}
Name: {trainee.nameEn || trainee.nameAr || ""}
{/* Course (English only, fallback to Arabic if EN missing) */}
Course: {(course.titleEn || course.titleAr || "")} ({course.code})
{/* Dates */}
Issued: {cert.issuedOn} • Exp: {cert.expiresOn}
{/* ID Number */}
ID Number: {trainee.idNumber || "-"}
{/* Photo */} {"photo" in design && design.photo.show && trainee.photoDataUrl && ( Photo )} {/* Logo */} {design.showLogo && (design.logoDataUrl || logo) && ( Logo )}
); } ReactDOM.createRoot(document.getElementById("dayim-training-app")).render();

Your list is empty, add products to the list to send a request

Return to Shop