Files
myAi/web/wwwroot/js/main.js
T
claude fc2dd721e4
Build and Push Docker Images / build (push) Successful in 29s
Initial commit
2026-05-02 21:31:31 +03:00

491 lines
23 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
var translations = {
ro: {
'brand.tagline': 'Romania dezvoltare applicatii',
'nav.products': 'Produse', 'nav.services': 'Servicii', 'nav.contact': 'Contactati-ne',
'hero.eyebrow': 'Portofoliu software easySoft',
'hero.title': 'Software pentru cabinete dentare, gestiune de stocuri si salvare sigura a datelor.',
'hero.text': 'Aplicatii practice construite pentru fluxuri reale de lucru: managementul pacientilor, contabilitate si gestiune, plus backup automatizat pentru fisiere importante.',
'hero.ctaPrimary': 'Vezi produsele', 'hero.ctaSecondary': 'Contactati-ne',
'hero.metric1': 'aplicații software', 'hero.metric2': 'ani experiență în dezvoltare', 'hero.metric3': 'instalări active',
'hero.cardLabel': 'Portofoliu software', 'hero.badge1': 'cabinete dentare', 'hero.badge2': 'gestiune si contabilitate', 'hero.badge3': 'salvare automata',
'products.eyebrow': 'Produse', 'products.title': 'Aplicatii software pentru activitati de zi cu zi', 'products.text': 'Portofoliul actual include aplicatii pentru cabinete stomatologice, operatiuni comerciale si protectia datelor.',
'products.easydent.title': 'Soft pentru cabinete stomatologice',
'products.easydent.desc': 'easyDent este un program destinat cabinetelor stomatologice si clinicilor dentare. Puteti urmari pacienti, plati, interventii, pacienti restantieri si profitul pe perioade de timp.',
'products.easydent.feature1': 'Planificarea pacientilor intr-o sectiune simplu de utilizat', 'products.easydent.feature2': 'Imagini dentare, istoric pe dinte si poze atasate pacientilor', 'products.easydent.feature3': 'Raport lunar CNAS si configurare pe specializari',
'products.easyerp.title': 'Soft de contabilitate si gestiunea stocurilor',
'products.easyerp.desc': 'easyERP este un program client-server, bazat pe SQL, compus din module pentru diferite divizii ale companiei: gestiune, contabilitate, facturare, livrari, comenzi si promotii.',
'products.easyerp.feature1': 'Receptie de marfa, inventar si cautare rapida in nomenclatoare', 'products.easyerp.feature2': 'Control pe roluri si drepturi de acces pe module', 'products.easyerp.feature3': 'Documente comerciale si rapoarte operationale',
'products.easybackup.title': 'Utilitar pentru salvarea fisierelor',
'products.easybackup.desc': 'easyBackup salveaza fisiere in directoare partajate sau pe servere FTP, cu job-uri recurente sau simple, monitorizare in timp si optiuni de compresie si notificare.',
'products.easybackup.feature1': 'Definire job-uri recurente sau simple', 'products.easybackup.feature2': 'Scanare directoare cu excluderi si filtre', 'products.easybackup.feature3': 'Compresie, parola si notificari prin e-mail',
'products.download': 'Descarca',
'services.eyebrow': 'Servicii', 'services.title': 'Servicii software si consultanta IT',
'services.db.title': 'Proiectare baze de date', 'services.db.text': 'Organizati mai bine informatiile si obtineti rapoartele de care aveti nevoie.',
'services.it.title': 'Consultanta IT', 'services.it.text': 'Analizam ofertele disponibile si alegem sistemul informatic potrivit pentru activitatea dumneavoastra.',
'services.dev.title': 'Dezvoltare software', 'services.dev.text': 'Construim aplicatii adaptate fluxului real de lucru, nu invers.',
'about.eyebrow': 'easySoft', 'about.title': 'Solutii software construite pentru lucru real',
'about.text1': 'Portofoliul easySoft acopera activitati esentiale pentru cabinete stomatologice, evidenta comerciala si protectia fisierelor importante.',
'about.text2': 'Aplicatiile sunt gandite pentru utilizare practica, implementare rapida si acces clar la informatiile care conteaza in activitatea zilnica.',
'about.point1Title': 'Implementare practica', 'about.point1Text': 'Produse software orientate spre utilizare zilnica.',
'about.point2Title': 'Fluxuri clare', 'about.point2Text': 'Planificare, evidenta, facturare, rapoarte si backup in functii usor de urmarit.',
'about.point3Title': 'Suport comercial direct', 'about.point3Text': 'Pentru prezentare, oferta sau implementare, puteti lua legatura direct cu easySoft.',
'contact.eyebrow': 'Contactati-ne', 'contact.title': 'Discutam despre nevoile tale software',
'contact.text': 'easySoft Romania dezvoltare applicatii. Pentru prezentari, detalii comerciale sau implementare, folositi datele de mai jos.',
'contact.personLabel': 'Persoana de contact', 'contact.addressLabel': 'Adresa', 'contact.phoneLabel': 'Telefon', 'contact.webLabel': 'Website',
'contact.form.name': 'Nume', 'contact.form.email': 'Email', 'contact.form.message': 'Mesaj', 'contact.form.send': 'Trimite mesaj',
'contact.form.yourname': 'Numele dumneavoastra', 'contact.form.youremail': 'nume@companie.ro', 'contact.form.yourmessage': 'Spuneti-ne ce produs sau serviciu va intereseaza.',
'contact.form.success': 'Va multumim pentru mesaj.', 'contact.form.submissionfailed': 'A aparut o eroare la transmiterea mesajului.', 'contact.form.verificationfailed': 'A aparut o eroare la verificare Captcha.',
'footer.backToTop': 'Inapoi sus',
'cookie.text': 'Folosim cookie-uri pentru a imbunatati experienta pe site, a analiza traficul si a personaliza continutul. Puteti accepta toate cookie-urile sau doar cele necesare.',
'cookie.privacy': 'Politica de confidentialitate',
'cookie.reject': 'Respinge',
'cookie.necessary': 'Doar necesare',
'cookie.accept': 'Accepta analitice',
'footer.rights': 'Toate drepturile rezervate'
},
en: {
'brand.tagline': 'Romania software development',
'nav.products': 'Products', 'nav.services': 'Services', 'nav.contact': 'Contact us',
'hero.eyebrow': 'easySoft software portfolio',
'hero.title': 'Software for dental offices, stock management and secure data backup.',
'hero.text': 'Practical applications built for real workflows: patient management, accounting and inventory, plus automated backup for critical files.',
'hero.ctaPrimary': 'View products', 'hero.ctaSecondary': 'Contact us',
'hero.metric1': 'software solutions', 'hero.metric2': 'years experience in software development', 'hero.metric3': 'active installations',
'hero.cardLabel': 'Software portfolio', 'hero.badge1': 'dental offices', 'hero.badge2': 'inventory and accounting', 'hero.badge3': 'automatic backup',
'products.eyebrow': 'Products', 'products.title': 'Software applications for daily operations', 'products.text': 'The current portfolio includes applications for dental offices, business operations and data protection.',
'products.easydent.title': 'Software for dental offices',
'products.easydent.desc': 'easyDent is built for dental offices and clinics. It helps track patients, payments, interventions, outstanding balances and profit over time.',
'products.easydent.feature1': 'Simple patient scheduling section', 'products.easydent.feature2': 'Dental images, tooth history and attached patient photos', 'products.easydent.feature3': 'Monthly reports and specialization-based setup',
'products.easyerp.title': 'Accounting and stock management software',
'products.easyerp.desc': 'easyERP is a client-server SQL-based application with modules for company divisions: inventory, accounting, invoicing, deliveries, orders and promotions.',
'products.easyerp.feature1': 'Receiving merchandise, inventory and fast search', 'products.easyerp.feature2': 'Role-based permissions for modules', 'products.easyerp.feature3': 'Commercial documents and operational reports',
'products.easybackup.title': 'File backup utility',
'products.easybackup.desc': 'easyBackup saves files to shared folders or FTP servers using recurring or one-time jobs, change tracking, compression and notifications.',
'products.easybackup.feature1': 'Recurring or one-time backup jobs', 'products.easybackup.feature2': 'Directory scanning with exclusions and filters', 'products.easybackup.feature3': 'Compression, password protection and email alerts',
'products.download': 'Download',
'services.eyebrow': 'Services', 'services.title': 'Software services and IT consulting',
'services.db.title': 'Database design', 'services.db.text': 'Organize information better and get the reports you actually need.',
'services.it.title': 'IT consulting', 'services.it.text': 'We review available systems and help choose the right software solution.',
'services.dev.title': 'Software development', 'services.dev.text': 'We build applications around the real workflow, not the other way around.',
'about.eyebrow': 'easySoft', 'about.title': 'Software solutions built for real work',
'about.text1': 'The easySoft portfolio covers essential workflows for dental offices, commercial operations and protection of important files.',
'about.text2': 'The applications are built for practical use, fast implementation and clear access to the information that matters every day.',
'about.point1Title': 'Practical implementation', 'about.point1Text': 'Software products focused on daily use.',
'about.point2Title': 'Clear workflows', 'about.point2Text': 'Scheduling, records, invoicing, reports and backup in functions that are easy to follow.',
'about.point3Title': 'Direct commercial support', 'about.point3Text': 'For presentation, pricing or implementation, you can contact easySoft directly.',
'contact.eyebrow': 'Contact us', 'contact.title': 'Lets discuss your software needs',
'contact.text': 'easySoft Romania software development. For product presentations, commercial details or implementation, use the contact details below.',
'contact.personLabel': 'Contact person', 'contact.addressLabel': 'Address', 'contact.phoneLabel': 'Phone', 'contact.webLabel': 'Website',
'contact.form.name': 'Name', 'contact.form.email': 'Email', 'contact.form.message': 'Message', 'contact.form.send': 'Send message',
'contact.form.yourname': 'Your name', 'contact.form.youremail': 'name@company.com', 'contact.form.yourmessage': 'Let us know how we can help you.',
'contact.form.success': 'Thank you for your message.', 'contact.form.submissionfailed': 'Failed to send the message.', 'contact.form.verificationfailed': 'Captcha verification failed.',
'footer.backToTop': 'Back to top',
'cookie.text': 'We use cookies to enhance your experience, analyze traffic and personalize content. You can accept all cookies or just the necessary ones.',
'cookie.privacy': 'Privacy policy',
'cookie.reject': 'Reject',
'cookie.necessary': 'Necessary only',
'cookie.accept': 'Accept analytics',
'footer.rights': 'All rights reserved'
}
};
function updateLegalLinks(lang) {
$('.legal-link').each(function () {
var $link = $(this);
if (lang === 'ro') {
$link.attr('href', $link.attr('data-ro-href'));
$link.text($link.attr('data-ro-text'));
} else {
$link.attr('href', $link.attr('data-en-href'));
$link.text($link.attr('data-en-text'));
}
});
}
function applyLanguage(lang) {
var dict = translations[lang] || translations.en;
$('[data-i18n]').each(function () {
var key = $(this).data('i18n');
if (!key) return;
// Handle special attributes like [placeholder]
var match = key.match(/^\[(.*?)\](.*)$/);
if (match) {
var attr = match[1]; // e.g. "placeholder"
var realKey = match[2]; // e.g. "contact.form.message"
if (dict[realKey]) {
$(this).attr(attr, dict[realKey]);
}
} else {
if (dict[key]) {
$(this).text(dict[key]);
}
}
});
updateLegalLinks(lang);
$('html').attr('lang', lang);
localStorage.setItem('easysoft-language', lang);
$('.lang-flag').each(function () {
var isActive = $(this).data('lang') === lang;
$(this).attr('aria-pressed', isActive ? 'true' : 'false');
$(this).toggleClass('is-active', isActive);
});
}
function detectLanguage() {
var saved = localStorage.getItem('easysoft-language');
if (saved && translations[saved]) {
return saved;
}
var browserLang = ((navigator.languages && navigator.languages[0]) || navigator.language || navigator.userLanguage || 'en').toLowerCase();
if (browserLang.indexOf('ro') === 0) {
return 'ro';
}
return 'en';
}
function closeMobileMenu() {
$('#mainNav').removeClass('is-open');
$('#menuToggle').attr('aria-expanded', 'false');
}
function initCarousels() {
$('[data-carousel]').each(function () {
var $carousel = $(this);
var $slides = $carousel.find('.carousel-slide');
var $dotsWrap = $carousel.find('.carousel-dots');
var index = 0;
var timer = null;
function renderDots() {
$dotsWrap.empty();
$slides.each(function (i) {
var $dot = $('<button>', {
type: 'button',
class: 'carousel-dot' + (i === index ? ' active' : ''),
'aria-label': 'Go to slide ' + (i + 1)
});
$dot.on('click', function () {
show(i);
restartAutoPlay();
});
$dotsWrap.append($dot);
});
}
function show(i) {
index = (i + $slides.length) % $slides.length;
$slides.removeClass('active').eq(index).addClass('active');
$dotsWrap.find('.carousel-dot').removeClass('active').eq(index).addClass('active');
}
function restartAutoPlay() {
if (timer) {
window.clearInterval(timer);
}
timer = window.setInterval(function () {
show(index + 1);
}, 5000);
}
$carousel.find('.prev').on('click', function () {
show(index - 1);
restartAutoPlay();
});
$carousel.find('.next').on('click', function () {
show(index + 1);
restartAutoPlay();
});
renderDots();
show(0);
restartAutoPlay();
});
}
(function ($) {
"use strict";
var reCaptchaSiteKey; // To be initialized from the backend API
var gTagManagerId; // Google Tag Manager ID from backend
var gMapKey; // To be initialized from the backend API
const CONSENT_KEY = "cookie_consent";
applyLanguage(detectLanguage());
$('.lang-flag').on('click', function () {
applyLanguage($(this).data('lang'));
});
$('#menuToggle').on('click', function () {
var $nav = $('#mainNav');
var open = !$nav.hasClass('is-open');
$nav.toggleClass('is-open', open);
$(this).attr('aria-expanded', open ? 'true' : 'false');
});
$('.nav a').on('click', function () {
closeMobileMenu();
});
$('#year').text(new Date().getFullYear());
/*--------------------------
API health check
---------------------------- */
// Checks the backend API live endpoint and updates #api-status if present.
function checkApiLive() {
var $statusEl = $('#api-status');
return $.ajax({
url: '/api/health/live',
method: 'GET',
dataType: 'json',
timeout: 5000
}).done(function (data) {
var status = (data && data.status) ? data.status : 'unknown';
if ($statusEl.length) {
$statusEl.text('API: ' + status).removeClass('text-danger').addClass('text-success');
} else {
console.log('API live status:', status);
}
}).fail(function (jqXHR, textStatus, errorThrown) {
if ($statusEl.length) {
$statusEl.text('API: offline').removeClass('text-success').addClass('text-danger');
}
console.error('API health check failed:', textStatus, errorThrown);
});
}
/*--------------------------
reCaptcha
---------------------------- */
function getRecaptchaWebKey() {
return $.get("/api/contact", function (res) {
reCaptchaSiteKey = res;
if (reCaptchaSiteKey) {
var script = document.createElement('script');
script.setAttribute('src', "https://www.google.com/recaptcha/api.js?render=" + reCaptchaSiteKey);
document.head.appendChild(script);
}
});
}
/*--------------------------
Google Tag Manager ID
---------------------------- */
function getGoogleTagManagerId() {
return $.get("/api/google/tagmanager", function (res) {
gTagManagerId = res;
});
}
/*--------------------------
Google Maps Key
---------------------------- */
function getGMapKey() {
return $.get("/api/google/maps", function (res) {
gMapKey = res;
if (gMapKey) {
var script = document.createElement('script');
script.setAttribute('src', "https://maps.googleapis.com/maps/api/js?key=" + gMapKey);
document.body.appendChild(script);
var script = document.createElement('script');
script.setAttribute('src', "js/mapcode.js");
document.body.appendChild(script);
}
});
}
/*--------------------------
Load Google Tag Manager script with the retrieved ID
---------------------------- */
function loadGoogleTagManager() {
if (window.__gtm_loaded) return;
var script = document.createElement('script');
script.async = true;
script.src = "https://www.googletagmanager.com/gtm/js?id=" + gTagManagerId;
document.head.appendChild(script);
// Initialize dataLayer
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'gtm.start': new Date().getTime(),
event: 'gtm.js'
});
}
/*--------------------------
Load consent cookie data
---------------------------- */
function loadConsent() {
var consent = getConsent();
if (!consent) {
showBanner();
} else {
applyConsent(consent);
showManage();
}
}
/*--------------------------
Preloader
---------------------------- */
$(window).on('load', async function () {
var pre_loader = $('#preloader')
try {
await Promise.all([
checkApiLive(),
getRecaptchaWebKey(),
getGoogleTagManagerId(),
getGMapKey()
]).then(loadConsent);
} catch (e) {
console.error("Startup API error", e);
}
pre_loader.fadeOut('slow', function () {
$(this).remove();
});
});
/*--------------------------
contact-from
---------------------------- */
$("#contactForm").on("submit", function (event) {
if (event.isDefaultPrevented()) {
// handle the invalid form...
formError();
submitMSG(false, "Did you fill in the form properly?");
} else {
// everything looks good!
event.preventDefault();
submitForm();
}
});
function submitForm() {
var loader = $('#contactLoader')
var button = $("#submit");
loader.css("display", "flex"); // show overlay
button.prop("disabled", true);
$("#msgSubmit").text("");
grecaptcha.ready(function () {
grecaptcha.execute(reCaptchaSiteKey, { action: 'contact' })
.then(function (token) {
// Initiate Variables With Form Content
var message = {
Name: $("#name").val(),
Email: $("#email").val(),
Subject: '[Contact request]',
Message: $("#message").val(),
CaptchaToken: token
};
$.ajax({
type: "POST",
url: "/api/contact",
data: JSON.stringify(message),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (resp) {
if (resp && resp.ok === true) {
formSuccess()
} else {
var dict = translations[detectLanguage()] || translations.en;
submitMSG(false, dict['contact.form.verificationfailed']);
}
},
error: function () {
var dict = translations[detectLanguage()] || translations.en;
submitMSG(false, dict['contact.form.submissionfailed']);
}
}).always(function () {
loader.hide();
button.prop("disabled", false);
});
});
});
}
function formSuccess() {
$("#contactForm")[0].reset();
var dict = translations[detectLanguage()] || translations.en;
submitMSG(true, dict['contact.form.success'])
}
function formError() {
$("#contactForm").removeClass().addClass('shake animated').one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function () {
$(this).removeClass();
});
}
function submitMSG(valid, msg) {
if (valid) {
var msgClasses = "text-center tada animated text-success";
} else {
var msgClasses = "text-center text-danger";
}
$("#msgSubmit").removeClass().addClass(msgClasses).text(msg);
}
/*--------------------------
cookie consent
---------------------------- */
function getConsent() {
try {
return JSON.parse(localStorage.getItem(CONSENT_KEY));
} catch {
return null;
}
}
function setConsent(consent) {
localStorage.setItem(CONSENT_KEY, JSON.stringify(consent));
}
function showBanner() { $("#cookieBanner").fadeIn(200); }
function hideBanner() { $("#cookieBanner").fadeOut(200); }
function showManage() { $("#cookieManage").show(); }
function applyConsent(consent) {
if (consent && consent.analytics === true) {
loadGoogleTagManager();
}
}
// Actions
$("#cookieReject, #cookieNecessary").on("click", function () {
setConsent({ necessary: true, analytics: false, ts: new Date().toISOString() });
hideBanner();
showManage();
location.reload(true);
});
$("#cookieAccept").on("click", function () {
setConsent({ necessary: true, analytics: true, ts: new Date().toISOString() });
hideBanner();
showManage();
applyConsent(getConsent());
location.reload(true);
});
$("#cookieManage").on("click", function (e) {
e.preventDefault();
showBanner();
});
initCarousels();
})(jQuery);