Changes
This commit is contained in:
+101
-3
@@ -433,6 +433,34 @@ img {
|
|||||||
margin-top: 14px
|
margin-top: 14px
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-message:empty {
|
||||||
|
display: none
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-message:not(:empty) {
|
||||||
|
padding: 10px 14px;
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 1px solid rgba(255,255,255,.08);
|
||||||
|
background: rgba(0,0,0,.18);
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1.4
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-message.text-success:not(:empty) {
|
||||||
|
background: rgba(126,242,167,.08);
|
||||||
|
border-color: rgba(126,242,167,.35)
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-message.text-danger:not(:empty) {
|
||||||
|
background: rgba(255,138,138,.08);
|
||||||
|
border-color: rgba(255,138,138,.35)
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-message.text-warning:not(:empty) {
|
||||||
|
background: rgba(247,212,136,.08);
|
||||||
|
border-color: rgba(247,212,136,.35)
|
||||||
|
}
|
||||||
|
|
||||||
.text-success {
|
.text-success {
|
||||||
color: #7ef2a7 !important
|
color: #7ef2a7 !important
|
||||||
}
|
}
|
||||||
@@ -441,6 +469,44 @@ img {
|
|||||||
color: #ff8a8a !important
|
color: #ff8a8a !important
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-warning {
|
||||||
|
color: #f7d488 !important
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-form {
|
||||||
|
margin-top: 28px;
|
||||||
|
padding: 28px;
|
||||||
|
border-radius: 24px;
|
||||||
|
background: rgba(255,255,255,.03);
|
||||||
|
border: 1px solid rgba(255,255,255,.08)
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-form h3 {
|
||||||
|
margin: 0 0 6px;
|
||||||
|
font-size: 1.1rem
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-form p {
|
||||||
|
margin: 0 0 14px;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: .92rem
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-form .subscribe-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
flex-wrap: wrap
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-form .subscribe-row input[type="email"] {
|
||||||
|
flex: 1 1 220px;
|
||||||
|
min-width: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-form .consent-inline {
|
||||||
|
margin-top: 12px
|
||||||
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
padding: 26px 0;
|
padding: 26px 0;
|
||||||
border-top: 1px solid rgba(255,255,255,.08);
|
border-top: 1px solid rgba(255,255,255,.08);
|
||||||
@@ -513,15 +579,47 @@ img {
|
|||||||
z-index: 80;
|
z-index: 80;
|
||||||
background: rgba(0,0,0,.55);
|
background: rgba(0,0,0,.55);
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center
|
justify-content: center;
|
||||||
|
backdrop-filter: blur(2px)
|
||||||
}
|
}
|
||||||
|
|
||||||
.loader-box {
|
.loader-box {
|
||||||
padding: 20px 30px;
|
max-width: 360px;
|
||||||
|
padding: 22px 28px;
|
||||||
border-radius: 18px;
|
border-radius: 18px;
|
||||||
background: #071326;
|
background: #071326;
|
||||||
border: 1px solid rgba(255,255,255,.16);
|
border: 1px solid rgba(255,255,255,.16);
|
||||||
font-weight: 800
|
text-align: center;
|
||||||
|
box-shadow: var(--shadow)
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader-box strong {
|
||||||
|
display: block;
|
||||||
|
font-weight: 800;
|
||||||
|
margin-bottom: 6px
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader-box span {
|
||||||
|
display: block;
|
||||||
|
color: var(--muted);
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: .92rem;
|
||||||
|
line-height: 1.5
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader-spinner {
|
||||||
|
display: block;
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
margin: 0 auto 14px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 3px solid rgba(255,255,255,.18);
|
||||||
|
border-top-color: #9cc5ff;
|
||||||
|
animation: loader-spin .8s linear infinite
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes loader-spin {
|
||||||
|
to { transform: rotate(360deg) }
|
||||||
}
|
}
|
||||||
|
|
||||||
.shake {
|
.shake {
|
||||||
|
|||||||
@@ -114,7 +114,7 @@
|
|||||||
<label for="gdprConsent" data-i18n="cv.gdpr">I agree that my CV is processed and stored.</label>
|
<label for="gdprConsent" data-i18n="cv.gdpr">I agree that my CV is processed and stored.</label>
|
||||||
</div>
|
</div>
|
||||||
<button id="matchSubmit" type="submit" class="btn btn-primary" data-i18n="cv.submit">Extract CV and match job</button>
|
<button id="matchSubmit" type="submit" class="btn btn-primary" data-i18n="cv.submit">Extract CV and match job</button>
|
||||||
<strong id="matcherMsg" class="form-message"></strong>
|
<strong id="matcherMsg" class="form-message" role="status" aria-live="polite"></strong>
|
||||||
</form>
|
</form>
|
||||||
<aside class="ai-panel result-panel">
|
<aside class="ai-panel result-panel">
|
||||||
<span class="eyebrow" data-i18n="cv.result">Result</span>
|
<span class="eyebrow" data-i18n="cv.result">Result</span>
|
||||||
@@ -163,7 +163,7 @@
|
|||||||
<textarea id="message" rows="6" data-i18n-placeholder="form.messagePlaceholder" placeholder="Tell me what you want to build." required></textarea>
|
<textarea id="message" rows="6" data-i18n-placeholder="form.messagePlaceholder" placeholder="Tell me what you want to build." required></textarea>
|
||||||
</label>
|
</label>
|
||||||
<button id="submit" type="submit" class="btn btn-primary" data-i18n="form.send">Send message</button>
|
<button id="submit" type="submit" class="btn btn-primary" data-i18n="form.send">Send message</button>
|
||||||
<strong id="msgSubmit" class="form-message"></strong>
|
<strong id="msgSubmit" class="form-message" role="status" aria-live="polite"></strong>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -184,8 +184,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
<div id="contactLoader" class="loader-overlay" style="display:none;">
|
<div id="contactLoader" class="loader-overlay" style="display:none;" role="status" aria-live="polite">
|
||||||
<div class="loader-box" data-i18n="status.sending">Sending...</div>
|
<div class="loader-box">
|
||||||
|
<span class="loader-spinner" aria-hidden="true"></span>
|
||||||
|
<strong data-i18n="status.sending">Sending...</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="cvLoader" class="loader-overlay" style="display:none;" role="status" aria-live="polite">
|
||||||
|
<div class="loader-box">
|
||||||
|
<span class="loader-spinner" aria-hidden="true"></span>
|
||||||
|
<strong data-i18n="cv.loaderTitle">Working on your CV</strong>
|
||||||
|
<span data-i18n="cv.loaderText">Extracting text, retrieving context and scoring the match. This can take a moment.</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="cookieBanner" class="cookie-overlay" style="display:none;">
|
<div id="cookieBanner" class="cookie-overlay" style="display:none;">
|
||||||
<div class="cookie-box">
|
<div class="cookie-box">
|
||||||
|
|||||||
+21
-3
@@ -138,6 +138,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
<form class="contact-form" id="contactForm">
|
<form class="contact-form" id="contactForm">
|
||||||
<label>
|
<label>
|
||||||
<span data-i18n="form.name">Name</span>
|
<span data-i18n="form.name">Name</span>
|
||||||
@@ -152,8 +153,22 @@
|
|||||||
<textarea id="message" rows="6" data-i18n-placeholder="form.messagePlaceholder" placeholder="Tell me what you want to build." required></textarea>
|
<textarea id="message" rows="6" data-i18n-placeholder="form.messagePlaceholder" placeholder="Tell me what you want to build." required></textarea>
|
||||||
</label>
|
</label>
|
||||||
<button id="submit" type="submit" class="btn btn-primary" data-i18n="form.send">Send message</button>
|
<button id="submit" type="submit" class="btn btn-primary" data-i18n="form.send">Send message</button>
|
||||||
<strong id="msgSubmit" class="form-message"></strong>
|
<strong id="msgSubmit" class="form-message" role="status" aria-live="polite"></strong>
|
||||||
</form>
|
</form>
|
||||||
|
<form class="subscribe-form" id="subscribeForm" novalidate>
|
||||||
|
<h3 data-i18n="subscribe.title">Stay in the loop</h3>
|
||||||
|
<p data-i18n="subscribe.text">Get a short note when a new AI demo is published. One email at most every few weeks.</p>
|
||||||
|
<div class="subscribe-row">
|
||||||
|
<input type="email" id="subscribeEmail" data-i18n-placeholder="subscribe.emailPlaceholder" placeholder="name@company.com" required />
|
||||||
|
<button id="subscribeSubmit" type="submit" class="btn btn-primary" data-i18n="subscribe.submit">Subscribe</button>
|
||||||
|
</div>
|
||||||
|
<div class="consent-inline">
|
||||||
|
<input type="checkbox" id="subscribeConsent" required />
|
||||||
|
<label for="subscribeConsent" data-i18n="subscribe.gdpr">I agree to receive occasional emails about new demos.</label>
|
||||||
|
</div>
|
||||||
|
<strong id="subscribeMsg" class="form-message" role="status" aria-live="polite"></strong>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
@@ -173,8 +188,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
<div id="contactLoader" class="loader-overlay" style="display:none;">
|
<div id="contactLoader" class="loader-overlay" style="display:none;" role="status" aria-live="polite">
|
||||||
<div class="loader-box" data-i18n="status.sending">Sending...</div>
|
<div class="loader-box">
|
||||||
|
<span class="loader-spinner" aria-hidden="true"></span>
|
||||||
|
<strong data-i18n="status.sending">Sending...</strong>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="cookieBanner" class="cookie-overlay" style="display:none;">
|
<div id="cookieBanner" class="cookie-overlay" style="display:none;">
|
||||||
<div class="cookie-box">
|
<div class="cookie-box">
|
||||||
|
|||||||
+102
-8
@@ -47,6 +47,15 @@
|
|||||||
"form.thanks": "Thank you for your message.",
|
"form.thanks": "Thank you for your message.",
|
||||||
"form.captchaFailed": "Captcha verification failed.",
|
"form.captchaFailed": "Captcha verification failed.",
|
||||||
"form.failed": "Failed to send the message.",
|
"form.failed": "Failed to send the message.",
|
||||||
|
"form.rateLimited": "Too many requests from your network. Please wait a moment and try again.",
|
||||||
|
"subscribe.title": "Stay in the loop",
|
||||||
|
"subscribe.text": "Get a short note when a new AI demo is published. One email at most every few weeks.",
|
||||||
|
"subscribe.emailPlaceholder": "name@company.com",
|
||||||
|
"subscribe.gdpr": "I agree to receive occasional emails about new demos.",
|
||||||
|
"subscribe.submit": "Subscribe",
|
||||||
|
"subscribe.thanks": "Thanks! You are subscribed.",
|
||||||
|
"subscribe.failed": "Could not subscribe right now. Please try again later.",
|
||||||
|
"subscribe.noConsent": "Please confirm your consent first.",
|
||||||
"footer.rights": "All rights reserved",
|
"footer.rights": "All rights reserved",
|
||||||
"footer.top": "Back to top",
|
"footer.top": "Back to top",
|
||||||
"legal.terms": "Terms",
|
"legal.terms": "Terms",
|
||||||
@@ -92,8 +101,11 @@
|
|||||||
"cv.processingLong": "Processing CV PDF and job input.",
|
"cv.processingLong": "Processing CV PDF and job input.",
|
||||||
"cv.cvFailed": "CV extraction failed",
|
"cv.cvFailed": "CV extraction failed",
|
||||||
"cv.matchFailed": "Job matching failed",
|
"cv.matchFailed": "Job matching failed",
|
||||||
|
"cv.rateLimited": "Too many CV matcher requests from your network. Please try again in a few minutes.",
|
||||||
"cv.completed": "Match completed.",
|
"cv.completed": "Match completed.",
|
||||||
"cv.backendMissing": "There was an error while processing the CV.",
|
"cv.backendMissing": "There was an error while processing the CV.",
|
||||||
|
"cv.loaderTitle": "Working on your CV",
|
||||||
|
"cv.loaderText": "Extracting text, retrieving context and scoring the match. This can take a moment.",
|
||||||
"cv.noSummary": "No summary returned.",
|
"cv.noSummary": "No summary returned.",
|
||||||
"cv.noItems": "No items returned.",
|
"cv.noItems": "No items returned.",
|
||||||
"cv.strengths": "Strengths",
|
"cv.strengths": "Strengths",
|
||||||
@@ -140,6 +152,15 @@
|
|||||||
"form.thanks": "Mulțumesc pentru mesaj.",
|
"form.thanks": "Mulțumesc pentru mesaj.",
|
||||||
"form.captchaFailed": "Verificarea Captcha a eșuat.",
|
"form.captchaFailed": "Verificarea Captcha a eșuat.",
|
||||||
"form.failed": "Mesajul nu a putut fi trimis.",
|
"form.failed": "Mesajul nu a putut fi trimis.",
|
||||||
|
"form.rateLimited": "Prea multe cereri din rețeaua ta. Te rugăm să aștepți câteva momente și să încerci din nou.",
|
||||||
|
"subscribe.title": "Rămâi la curent",
|
||||||
|
"subscribe.text": "Primești o notă scurtă când publicăm un nou demo AI. Cel mult un email la câteva săptămâni.",
|
||||||
|
"subscribe.emailPlaceholder": "nume@companie.ro",
|
||||||
|
"subscribe.gdpr": "Sunt de acord să primesc ocazional emailuri despre noile demo-uri.",
|
||||||
|
"subscribe.submit": "Abonează-mă",
|
||||||
|
"subscribe.thanks": "Mulțumesc! Ești abonat.",
|
||||||
|
"subscribe.failed": "Nu am putut realiza abonarea acum. Te rugăm să încerci mai târziu.",
|
||||||
|
"subscribe.noConsent": "Te rugăm să confirmi întâi consimțământul.",
|
||||||
"footer.rights": "Toate drepturile rezervate",
|
"footer.rights": "Toate drepturile rezervate",
|
||||||
"footer.top": "Înapoi sus",
|
"footer.top": "Înapoi sus",
|
||||||
"legal.terms": "Termeni",
|
"legal.terms": "Termeni",
|
||||||
@@ -185,8 +206,11 @@
|
|||||||
"cv.processingLong": "Se procesează PDF-ul și informațiile despre job.",
|
"cv.processingLong": "Se procesează PDF-ul și informațiile despre job.",
|
||||||
"cv.cvFailed": "Extragerea CV-ului a eșuat",
|
"cv.cvFailed": "Extragerea CV-ului a eșuat",
|
||||||
"cv.matchFailed": "Matching-ul jobului a eșuat",
|
"cv.matchFailed": "Matching-ul jobului a eșuat",
|
||||||
|
"cv.rateLimited": "Prea multe cereri către CV matcher din rețeaua ta. Te rugăm să încerci din nou peste câteva minute.",
|
||||||
"cv.completed": "Matching finalizat.",
|
"cv.completed": "Matching finalizat.",
|
||||||
"cv.backendMissing": "A aparut o eroare la pcocesarea CV-ului.",
|
"cv.backendMissing": "A aparut o eroare la pcocesarea CV-ului.",
|
||||||
|
"cv.loaderTitle": "Procesăm CV-ul tău",
|
||||||
|
"cv.loaderText": "Extragem textul, recuperăm contextul și calculăm scorul potrivirii. Poate dura câteva momente.",
|
||||||
"cv.noSummary": "Nu a fost returnat niciun sumar.",
|
"cv.noSummary": "Nu a fost returnat niciun sumar.",
|
||||||
"cv.noItems": "Nu au fost returnate elemente.",
|
"cv.noItems": "Nu au fost returnate elemente.",
|
||||||
"cv.strengths": "Puncte forte",
|
"cv.strengths": "Puncte forte",
|
||||||
@@ -364,8 +388,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function submitMSG(valid, msg) {
|
function submitMSG(valid, msg, severity) {
|
||||||
$('#msgSubmit').removeClass().addClass(valid ? 'form-message text-success' : 'form-message text-danger').text(msg);
|
var tone = valid ? 'text-success' : ('text-' + (severity || 'danger'));
|
||||||
|
$('#msgSubmit').removeClass().addClass('form-message ' + tone).text(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
function formSuccess() {
|
function formSuccess() {
|
||||||
@@ -404,8 +429,9 @@
|
|||||||
}).done(function (resp) {
|
}).done(function (resp) {
|
||||||
if (resp && resp.ok === true) formSuccess();
|
if (resp && resp.ok === true) formSuccess();
|
||||||
else submitMSG(false, t('form.captchaFailed'));
|
else submitMSG(false, t('form.captchaFailed'));
|
||||||
}).fail(function () {
|
}).fail(function (jqXHR) {
|
||||||
submitMSG(false, t('form.failed'));
|
var isRateLimited = jqXHR && jqXHR.status === 429;
|
||||||
|
submitMSG(false, isRateLimited ? t('form.rateLimited') : t('form.failed'), isRateLimited ? 'warning' : 'danger');
|
||||||
formError();
|
formError();
|
||||||
}).always(function () {
|
}).always(function () {
|
||||||
loader.hide();
|
loader.hide();
|
||||||
@@ -454,10 +480,11 @@
|
|||||||
$msg.removeClass().addClass('form-message text-danger').text(t('cv.noConsent'));
|
$msg.removeClass().addClass('form-message text-danger').text(t('cv.noConsent'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
var $cvLoader = $('#cvLoader');
|
||||||
$button.prop('disabled', true).text(t('cv.processing'));
|
$button.prop('disabled', true).text(t('cv.processing'));
|
||||||
$msg.removeClass().addClass('form-message').text(t('cv.extracting'));
|
$msg.removeClass().addClass('form-message').text(t('cv.extracting'));
|
||||||
$result.html('<div class="empty-result">' + escapeHtml(t('cv.processingLong')) + '</div>');
|
$result.html('<div class="empty-result">' + escapeHtml(t('cv.processingLong')) + '</div>');
|
||||||
|
$cvLoader.css('display', 'flex');
|
||||||
|
|
||||||
if (window.grecaptcha && reCaptchaSiteKey) {
|
if (window.grecaptcha && reCaptchaSiteKey) {
|
||||||
grecaptcha.ready(function () {
|
grecaptcha.ready(function () {
|
||||||
@@ -466,7 +493,7 @@
|
|||||||
}).then(postCv);
|
}).then(postCv);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Captcha unavailable: show clear error and restore UI
|
$cvLoader.hide();
|
||||||
$msg.removeClass().addClass('form-message text-danger').text(t('form.captchaFailed'));
|
$msg.removeClass().addClass('form-message text-danger').text(t('form.captchaFailed'));
|
||||||
$button.prop('disabled', false).text(t('cv.submit'));
|
$button.prop('disabled', false).text(t('cv.submit'));
|
||||||
return;
|
return;
|
||||||
@@ -481,6 +508,7 @@
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: formData
|
body: formData
|
||||||
});
|
});
|
||||||
|
if (cvResponse.status === 429) throw new Error(t('cv.rateLimited'));
|
||||||
if (!cvResponse.ok) throw new Error(t('cv.cvFailed'));
|
if (!cvResponse.ok) throw new Error(t('cv.cvFailed'));
|
||||||
var cvData = await cvResponse.json();
|
var cvData = await cvResponse.json();
|
||||||
// Before calling match, obtain a fresh captcha token for the match action
|
// Before calling match, obtain a fresh captcha token for the match action
|
||||||
@@ -511,21 +539,87 @@
|
|||||||
captchaToken: matchToken
|
captchaToken: matchToken
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
if (matchResponse.status === 429) throw new Error(t('cv.rateLimited'));
|
||||||
if (!matchResponse.ok) throw new Error(t('cv.matchFailed'));
|
if (!matchResponse.ok) throw new Error(t('cv.matchFailed'));
|
||||||
var match = await matchResponse.json();
|
var match = await matchResponse.json();
|
||||||
renderMatchResult(match);
|
renderMatchResult(match);
|
||||||
$msg.removeClass().addClass('form-message text-success').text(t('cv.completed'));
|
$msg.removeClass().addClass('form-message text-success').text(t('cv.completed'));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
$msg.removeClass().addClass('form-message text-danger').text(err.message || t('cv.matchFailed'));
|
var isRateLimited = err && err.message === t('cv.rateLimited');
|
||||||
$result.html('<div class="empty-result">' + escapeHtml(t('cv.backendMissing')) + '</div>');
|
var tone = isRateLimited ? 'text-warning' : 'text-danger';
|
||||||
|
$msg.removeClass().addClass('form-message ' + tone).text(err.message || t('cv.matchFailed'));
|
||||||
|
$result.html('<div class="empty-result">' + escapeHtml(isRateLimited ? t('cv.rateLimited') : t('cv.backendMissing')) + '</div>');
|
||||||
} finally {
|
} finally {
|
||||||
|
$cvLoader.hide();
|
||||||
$button.prop('disabled', false).text(t('cv.submit'));
|
$button.prop('disabled', false).text(t('cv.submit'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#subscribeForm').on('submit', function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
var $msg = $('#subscribeMsg');
|
||||||
|
var $button = $('#subscribeSubmit');
|
||||||
|
var $loader = $('#contactLoader');
|
||||||
|
var email = $('#subscribeEmail').val();
|
||||||
|
var consent = $('#subscribeConsent').is(':checked');
|
||||||
|
|
||||||
|
function setMsg(severity, key) {
|
||||||
|
$msg.removeClass().addClass('form-message text-' + severity).text(t(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!consent) {
|
||||||
|
setMsg('danger', 'subscribe.noConsent');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!email) {
|
||||||
|
setMsg('danger', 'form.failed');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$loader.css('display', 'flex');
|
||||||
|
$button.prop('disabled', true);
|
||||||
|
$msg.removeClass().addClass('form-message').text('');
|
||||||
|
|
||||||
|
function postSubscribe(token) {
|
||||||
|
$.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
url: '/api/contact/subscribe',
|
||||||
|
data: JSON.stringify({ Email: email, CaptchaToken: token || '' }),
|
||||||
|
contentType: 'application/json; charset=utf-8',
|
||||||
|
dataType: 'json'
|
||||||
|
}).done(function (resp) {
|
||||||
|
if (resp && resp.ok === true) {
|
||||||
|
$('#subscribeForm')[0].reset();
|
||||||
|
setMsg('success', 'subscribe.thanks');
|
||||||
|
} else {
|
||||||
|
setMsg('danger', 'form.captchaFailed');
|
||||||
|
}
|
||||||
|
}).fail(function (jqXHR) {
|
||||||
|
if (jqXHR && jqXHR.status === 429) {
|
||||||
|
setMsg('warning', 'form.rateLimited');
|
||||||
|
} else {
|
||||||
|
setMsg('danger', 'subscribe.failed');
|
||||||
|
}
|
||||||
|
}).always(function () {
|
||||||
|
$loader.hide();
|
||||||
|
$button.prop('disabled', false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.grecaptcha && reCaptchaSiteKey) {
|
||||||
|
grecaptcha.ready(function () {
|
||||||
|
grecaptcha.execute(reCaptchaSiteKey, { action: 'contact' }).then(postSubscribe);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$loader.hide();
|
||||||
|
$button.prop('disabled', false);
|
||||||
|
setMsg('danger', 'form.captchaFailed');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function renderMatchResult(match) {
|
function renderMatchResult(match) {
|
||||||
var score = match.score || match.matchScore || 0;
|
var score = match.score || match.matchScore || 0;
|
||||||
var summary = match.summary || t('cv.noSummary');
|
var summary = match.summary || t('cv.noSummary');
|
||||||
|
|||||||
Reference in New Issue
Block a user