WorkHours

Work Hours Tracker
Work Hours
Daily time tracker
Today
Daily tracking
Name (for report)
This name is saved and will appear automatically every time you open the app.
Contract
Month
Jan 2026
04 Dec
Thursday • Day 04
Daily alert
Hours today
Holiday / OFF
Monthly overview
Ready for export
Total hours
0
This contract
Days worked
0
OFF days
0
Calendar for
Jan 2026
Hours
Holiday / OFF
OFF days will appear as empty, colored cells in the PDF.
Companies
Saved companies will appear here. Tap a company to view its archive.
Archive
Months with saved hours (last 12 months) will appear here so you can quickly review them.
`;const win = window.open("", "_blank"); if (!win) { alert("Popup blocked. Please allow popups to generate the PDF."); return; } win.document.open(); win.document.write(html); win.document.close(); win.focus(); win.print(); }generatePdfBtn.addEventListener("click", generatePdfReport);const translations = { en: { app_name: "Work Hours", app_subtitle: "Daily time tracker", section_today: "Today", badge_daily_tracking: "Daily tracking", label_username: "Name (for report)", hint_username_saved: "This name is saved and will appear automatically every time you open the app.", label_contract: "Contract", label_month: "Month", daily_alert_label: "Daily alert", label_hours: "Hours today", label_off: "Holiday / OFF", off_button: "Mark as OFF", btn_save_today: "Save today", btn_open_calendar: "Open calendar", section_month: "Monthly overview", badge_report_hint: "Ready for export", summary_total_hours: "Total hours", summary_days_worked: "Days worked", summary_off_days: "OFF days", summary_for_contract: "This contract", summary_empty: "Add a contract and save your first day to see your monthly overview.", btn_generate_pdf: "Generate PDF report", btn_toggle_calendar: "Show / hide calendar", hint_pdf_color: "OFF days will appear as empty, colored cells in the PDF.", calendar_for: "Calendar for", btn_save_day: "Save day", btn_clear_day: "Clear", section_companies: "Companies", companies_empty: "Saved companies will appear here. Tap a company to view its archive.", section_archive: "Archive", archive_empty: "Months with saved hours (last 12 months) will appear here so you can quickly review them.", footer_for_mr: "Designed specifically for Mr. Alaa Al-Bardawil.", footer_designed_by: "Designed by", btn_save_company: "Save company", alert_contract_required: "Please enter the company name for your contract first.", alert_hours_required: "Please enter working hours or mark the day as OFF.", alert_saved_today: "Today's entry has been saved.", alert_saved_day: "The selected day has been saved.", alert_daily_popup: "The application will remind you when you open it if you missed past days with no hours.", alert_company_saved: "Company saved.", alert_company_exists: "This company is already saved and selected.", missing_days_alert_title: "You have past days with no working hours recorded:", missing_days_alert_suffix: "Please enter your working hours or mark these days as OFF.", install_prompt_title: "Save this app?", install_prompt_body: "Would you like to save this time-tracking app on your device for quick access? If you accept, please use your browser's \"Add to Home screen\" or \"Install app\" option.", install_prompt_later: "Not now", install_prompt_save: "Save app", install_saved_banner: "This app is saved on your device. If you add it again, your shortcut will update.", install_save_instructions: "To save this app on your device, open your browser menu and choose \"Add to Home screen\" or \"Install app\". Your shortcut will open this app directly." }, ar: { app_name: "ساعات العمل", app_subtitle: "تسجيل الوقت اليومي", section_today: "اليوم", badge_daily_tracking: "تتبع يومي", label_username: "الاسم (للتقرير)", hint_username_saved: "سيتم حفظ هذا الاسم ويظهر تلقائيًا كل مرة تفتح فيها التطبيق.", label_contract: "العقد", label_month: "الشهر", daily_alert_label: "تنبيه يومي", label_hours: "ساعات اليوم", label_off: "إجازة / OFF", off_button: "تحديد كيوم إجازة", btn_save_today: "حفظ يوم اليوم", btn_open_calendar: "فتح التقويم", section_month: "ملخص الشهر", badge_report_hint: "جاهز للتصدير", summary_total_hours: "إجمالي الساعات", summary_days_worked: "أيام العمل", summary_off_days: "أيام الإجازة", summary_for_contract: "هذا العقد", summary_empty: "أضف عقدًا واحفظ اليوم الأول لعرض ملخص الشهر.", btn_generate_pdf: "إنشاء تقرير PDF", btn_toggle_calendar: "عرض / إخفاء التقويم", hint_pdf_color: "أيام الإجازة تظهر كخانات فارغة ملونة في ملف الـ PDF.", calendar_for: "التقويم لـ", btn_save_day: "حفظ اليوم", btn_clear_day: "مسح", section_companies: "الشركات", companies_empty: "ستظهر هنا الشركات المحفوظة. اضغط على شركة لعرض أرشيفها.", section_archive: "الأرشيف", archive_empty: "الأشهر التي تحتوي على ساعات محفوظة (آخر سنة) ستظهر هنا لمراجعتها بسرعة.", footer_for_mr: "مصمم خصيصًا للأستاذ علاء البرادويل.", footer_designed_by: "تصميم", btn_save_company: "حفظ الشركة", alert_contract_required: "يرجى إدخال اسم الشركة المتعاقد معها أولاً.", alert_hours_required: "يرجى إدخال ساعات العمل أو تحديد اليوم كيوم إجازة.", alert_saved_today: "تم حفظ إدخال اليوم.", alert_saved_day: "تم حفظ اليوم المحدد.", alert_daily_popup: "سيذكّرك التطبيق عند فتحه إذا نسيت إدخال الساعات للأيام السابقة.", alert_company_saved: "تم حفظ الشركة.", alert_company_exists: "هذه الشركة محفوظة بالفعل وتم اختيارها.", missing_days_alert_title: "لديك أيام سابقة بدون تسجيل ساعات عمل:", missing_days_alert_suffix: "يرجى إدخال ساعات العمل أو تحديد هذه الأيام كإجازة.", install_prompt_title: "حفظ هذا التطبيق؟", install_prompt_body: "هل تريد حفظ هذا التطبيق على جهازك للوصول السريع؟ إذا وافقت، استخدم خيار \"إضافة إلى الشاشة الرئيسية\" أو \"تثبيت التطبيق\" من متصفحك.", install_prompt_later: "لاحقًا", install_prompt_save: "حفظ التطبيق", install_saved_banner: "هذا التطبيق محفوظ على جهازك. إذا أضفته مرة أخرى سيتم تحديث الاختصار.", install_save_instructions: "لحفظ هذا التطبيق على جهازك، افتح قائمة المتصفح واختر \"إضافة إلى الشاشة الرئيسية\" أو \"تثبيت التطبيق\". سيقوم الاختصار بفتح هذا التطبيق مباشرة." }, de: { app_name: "Arbeitsstunden", app_subtitle: "Täglicher Zeit-Tracker", section_today: "Heute", badge_daily_tracking: "Tägliche Erfassung", label_username: "Name (für Bericht)", hint_username_saved: "Dieser Name wird gespeichert und erscheint automatisch jedes Mal, wenn Sie die App öffnen.", label_contract: "Vertrag", label_month: "Monat", daily_alert_label: "Tägliche Erinnerung", label_hours: "Stunden heute", label_off: "Feiertag / Frei", off_button: "Als frei markieren", btn_save_today: "Heute speichern", btn_open_calendar: "Kalender öffnen", section_month: "Monatsübersicht", badge_report_hint: "Bereit zum Export", summary_total_hours: "Gesamtstunden", summary_days_worked: "Arbeitstage", summary_off_days: "Freie Tage", summary_for_contract: "Dieser Vertrag", summary_empty: "Fügen Sie einen Vertrag hinzu und speichern Sie den ersten Tag, um die Monatsübersicht zu sehen.", btn_generate_pdf: "PDF-Bericht erstellen", btn_toggle_calendar: "Kalender ein/ausblenden", hint_pdf_color: "Freie Tage erscheinen als leere, farbige Felder im PDF.", calendar_for: "Kalender für", btn_save_day: "Tag speichern", btn_clear_day: "Löschen", section_companies: "Unternehmen", companies_empty: "Gespeicherte Unternehmen erscheinen hier. Tippen Sie auf ein Unternehmen, um sein Archiv zu sehen.", section_archive: "Archiv", archive_empty: "Monate mit gespeicherten Stunden (letzte 12 Monate) erscheinen hier zur schnellen Einsicht.", footer_for_mr: "Speziell entworfen für Herrn Alaa Al-Bardawil.", footer_designed_by: "Entworfen von", btn_save_company: "Unternehmen speichern", alert_contract_required: "Bitte geben Sie zuerst den Firmennamen des Vertrags ein.", alert_hours_required: "Bitte geben Sie Arbeitsstunden ein oder markieren Sie den Tag als frei.", alert_saved_today: "Der heutige Eintrag wurde gespeichert.", alert_saved_day: "Der ausgewählte Tag wurde gespeichert.", alert_daily_popup: "Die App erinnert Sie beim Öffnen, wenn frühere Tage ohne Stunden vorhanden sind.", alert_company_saved: "Unternehmen gespeichert.", alert_company_exists: "Dieses Unternehmen ist bereits gespeichert und ausgewählt.", missing_days_alert_title: "Sie haben vergangene Tage ohne erfasste Arbeitsstunden:", missing_days_alert_suffix: "Bitte tragen Sie Ihre Arbeitsstunden ein oder markieren Sie diese Tage als frei.", install_prompt_title: "App speichern?", install_prompt_body: "Möchten Sie diese Zeiterfassungs-App auf Ihrem Gerät für den schnellen Zugriff speichern? Wenn ja, verwenden Sie bitte im Browser \"Zum Startbildschirm hinzufügen\" oder \"App installieren\".", install_prompt_later: "Später", install_prompt_save: "App speichern", install_saved_banner: "Diese App ist auf Ihrem Gerät gespeichert. Wenn Sie sie erneut hinzufügen, wird die Verknüpfung aktualisiert.", install_save_instructions: "Um diese App auf Ihrem Gerät zu speichern, öffnen Sie das Browser-Menü und wählen Sie \"Zum Startbildschirm hinzufügen\" oder \"App installieren\". Die Verknüpfung öffnet direkt diese App." } };function applyLanguage(lang) { const dict = translations[lang] || translations.en; document.querySelectorAll("[data-i18n]").forEach((el) => { const key = el.getAttribute("data-i18n"); if (dict[key]) el.textContent = dict[key]; }); if (lang === "ar") { document.documentElement.setAttribute("dir", "rtl"); document.body.style.textAlign = "right"; } else { document.documentElement.setAttribute("dir", "ltr"); document.body.style.textAlign = "left"; } updateMonthLabel(); renderCalendar(); renderArchive(); renderCompanies(); updateTodayCard(); }languageSwitch.addEventListener("click", (e) => { if (e.target.matches("button[data-lang]")) { const lang = e.target.getAttribute("data-lang"); state.settings.language = lang; document .querySelectorAll("#languageSwitch button") .forEach((btn) => btn.classList.remove("active")); e.target.classList.add("active"); applyLanguage(lang); saveState(state); } });// Install prompt helpers function maybeShowInstallPrompt() { if (!state.settings.installPromptShown) { installModal.hidden = false; } else if (state.settings.installSaved) { installBanner.hidden = false; } else { installBanner.hidden = true; } }installLaterBtn.addEventListener("click", () => { state.settings.installPromptShown = true; saveState(state); installModal.hidden = true; });installSaveBtn.addEventListener("click", () => { state.settings.installPromptShown = true; state.settings.installSaved = true; saveState(state); installModal.hidden = true; installBanner.hidden = false; alert(currentTranslations().install_save_instructions); });function initFromState() { const lang = state.settings.language || "en"; document .querySelectorAll("#languageSwitch button") .forEach((btn) => { btn.classList.toggle("active", btn.getAttribute("data-lang") === lang); }); applyLanguage(lang); applyTheme();alertToggle.checked = !!state.settings.dailyAlertEnabled;renderContractList();if (state.ui.activeContract && !state.contracts.includes(state.ui.activeContract)) { state.contracts.push(state.ui.activeContract); } contractInput.value = state.ui.activeContract || ""; usernameInput.value = state.settings.username || "";updateMonthLabel(); updateTodayCard();renderCalendar(); recalcSummary(); renderCompanies(); renderArchive();maybeShowInstallPrompt(); maybeShowMissingDaysAlert(); }initFromState();
Open chat
Hello
Can we help you?