File: //var/www/quadcode.com/src/components/form/Form.svelte
<script lang="ts">
import Validation from '$utils/Validation';
import { localeLink } from '$lib/translations';
import InputField from './input/InputField.svelte';
import TextareaField from './input/TextareaField.svelte';
import CheckboxField from './input/CheckboxField.svelte';
import Message from './message/Message.svelte';
import InputFieldPhone from './input/InputFieldPhone.svelte';
import Button from '../button/Button.svelte';
import { browser } from '$app/environment';
import type { IForm } from '$type/form';
import createEvent from '$utils/createEvents';
import { env } from '$env/dynamic/public';
import { t } from '$lib/translations'
import logoImage from '../../assets/logo-short-black.svg';
import { getCookieByName } from '$utils/cookie';
export let logo = false;
export let formTitle = '';
export let formDescription = '';
let roistatId = null;
if (browser) {
const urlParams = new URLSearchParams(window.location.search);
const entries = urlParams.entries();
for (const entry of entries) {
localStorage.setItem('param__' + entry[0], entry[1]);
}
roistatId = getCookieByName('roistat_visit', document.cookie);
}
const formState: IForm = {
loading: false,
error: false,
data: {
first_name: '',
email: '',
tg: '',
phone: '',
message: '',
terms_agree: false,
roistatId,
},
response: {},
status: 0,
};
const sendForm = async () => {
formState.loading = true;
const code = document.querySelector('.iti__selected-dial-code');
const token = document.querySelector('.g-recaptcha-response');
for (let i = 0; i < localStorage.length; i++) {
let key = localStorage.key(i);
if (key && key.includes('param__')) {
formState.data[key.replace('param__', '')] = localStorage.getItem(key) || null;
}
}
if (code) {
formState.data.code = code.innerHTML;
}
let phone = formState.data.phone;
if (phone) {
if (String(phone).includes(String(formState.data.code))) {
phone = formState.data.phone;
} else {
phone = String(formState.data.code) + String(formState.data.phone);
}
delete formState.data.code;
}
if (token) {
formState.data.token = token?.value;
}
formState.data['landing_url'] = window.location.host + window.location.pathname;
formState.data['referrer'] = window.location.href;
formState.data['language'] = document.documentElement.lang;
formState.data['lang_by_browser'] = document.documentElement.lang;
for (const [key, value] of Object.entries(formState.data)) {
Validation({ name: key, value: value, formState });
}
if (Object.values(formState.response).length) {
formState.loading = false;
return;
}
createEvent({ event: 'saas_form_sent' });
await fetch(`/api/popup`, {
method: 'POST',
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
...formState.data,
phone: String(phone).replace(/[^+\d]/g, ''),
}),
})
.then((response) => {
formState.status = response.status;
return response.json();
})
.then((response) => {
formState.response = response;
})
.finally(() => {
formState.loading = false;
const grecaptcha = window?.grecaptcha;
if (grecaptcha && grecaptcha?.ready && env?.PUBLIC_RECAPTCHA_SITE_KEY) {
grecaptcha?.reset();
}
});
};
const clickSendMore = () => {
formState.data = {};
formState.response = {};
formState.status = 0;
const grecaptcha = window?.grecaptcha;
if (grecaptcha && grecaptcha?.ready && env?.PUBLIC_RECAPTCHA_SITE_KEY) {
grecaptcha?.reset();
}
};
</script>
<div class="form__form" >
{#if logo}
<img class="form__formLogo" src={logoImage} alt="logo">
{/if}
<div class="form__formText">
<p class="form__formTitle">{formTitle}</p>
<p class="form__formDescription">{formDescription}</p>
</div>
<div class="form__formItems">
<div class="form__formItem">
<InputField
className="bordered"
placeholder={$t("prop-firm.Name*")}
name="first_name"
error={formState.response.first_name}
value={String(formState.data.first_name || '')}
onChange={(e) => {
formState.data.first_name = e.currentTarget.value;
Validation({ name: 'first_name', value: e.currentTarget.value, formState });
}}
/>
</div>
<div class="form__formItem">
<InputField
className="bordered"
placeholder={$t("prop-firm.Email*")}
name="email"
error={formState.response.email}
value={String(formState.data.email || '')}
onChange={(e) => {
formState.data.email = e.currentTarget.value;
Validation({ name: 'email', value: e.currentTarget.value, formState });
}}
/>
</div>
<div class="form__formItem">
<InputFieldPhone
className="bordered"
placeholder={$t("prop-firm.Phone number*")}
name="phone"
error={formState.response.phone}
value={String(formState.data.phone || '')}
onChange={(e) => {
formState.data.phone = e.currentTarget.value;
Validation({ name: 'phone', value: e.currentTarget.value, formState });
}}
/>
</div>
<div class="form__formItem">
<InputField
className="bordered"
placeholder={$t("prop-firm.TG @username")}
name="tg"
error={formState.response.tg}
value={String(formState.data.tg || '')}
onChange={(e) => {
formState.data.tg = e.currentTarget.value;
Validation({ name: 'tg', value: e.currentTarget.value, formState });
}}
/>
</div>
<div class="form__formItem">
<TextareaField
className="bordered"
placeholder={$t("prop-firm.Comment")}
name="message"
error={formState.response.text}
value={String(formState.data.message || '')}
onChange={(e) => {
formState.data.message = e.currentTarget.value;
}}
/>
</div>
<div class="form__formItem">
<Button
text={$t("prop-firm.Get Started")}
className="form__button"
onClick={sendForm}
loading={formState.loading}
/>
</div>
<div class="form__formItem">
<CheckboxField
placeholder={`${$t("By sticking this checkbox I consent with the")} <a href="${localeLink()}/terms-and-conditions">${$t("terms and conditions")}</a> ${$t('and the')} <a href="${localeLink()}/privacy-policy">${$t('policy of the website')}</a>`}
name="terms_agree"
error={formState.response.terms_agree}
checked={Boolean(formState.data.terms_agree)}
onChange={(e) => {
formState.data.agreement = e.currentTarget.checked;
formState.data.terms_agree = e.currentTarget.checked;
Validation({ name: 'terms_agree', value: e.currentTarget.checked, formState });
}}
/>
</div>
</div>
{#if formState.response?.status === 'ok'}
<Message
onClick={clickSendMore}
text={$t("prop-firm.Thank you for your interest! Our team will contact you shortly to discuss the details.")}
/>
{/if}
{#if [500, 502, 429].includes(formState.status)}
<Message
error={true}
onClick={clickSendMore}
text={formState.response.error || formState.response.message || ''}
/>
{/if}
</div>
<style lang="scss">
@import 'src/scss/media';
@import 'src/scss/mixins';
@import 'src/scss/variables';
.form {
&__form {
background: #FFFFFF;
display: flex;
flex-direction: column;
gap: 16px;
padding: 52px 48.5px;
border-radius: 40px;
justify-content: center;
align-items: center;
width: 708px;
@include breakpoint-down('deskL') {
width: 492px;
gap: 29px;
padding: 33px 20px 32px 20px;
border-radius: 20px;
}
@include breakpoint-down('tabL') {
width: 346px;
gap: 22px;
}
@include breakpoint-down('tabM') {
width: 100%;
padding: 32px 14px 14px 14px;
gap: 25px;
}
}
&__formText {
padding-bottom: 24px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 16px;
@include breakpoint-down('deskL') {
gap: 13px;
padding-bottom: 0;
}
@include breakpoint-down('tabL') {
gap: 6px;
}
@include breakpoint-down('tabM') {
gap: 13px;
}
}
&__formLogo {
width: 184px;
height: 32px;
@include breakpoint-down('tabL') {
margin-bottom: -4px;
}
}
&__overTitle {
color: $redPrimary;
font-size: 20px;
line-height: 24px;
font-weight: 700;
@include breakpoint-down('deskL') {
font-size: 14px;
line-height: 15.4px;
}
@include breakpoint-down('tabL') {
font-size: 16px;
line-height: 22.4px;
}
@include breakpoint-down('tabM') {
line-height: 17.6px;
}
}
&__formTitle {
@include H2;
text-align: center;
@include breakpoint-down('deskL') {
width: 352px;
}
@include breakpoint-down('tabL') {
width: 251px;
}
@include breakpoint-down('tabM') {
@include H2;
width: 233px;
}
}
&__formDescription {
@include body;
text-align: center;
padding-inline: 13px;
@include breakpoint-down('deskL') {
@include subtext;
padding: 0;
}
@include breakpoint-down('tabL') {
@include table;
font-weight: 400;
}
@include breakpoint-down('tabM') {
@include body;
}
}
&__formItems {
padding-inline: 11.5px;
@include breakpoint-down('tabM') {
padding-inline: 0;
}
}
&__formItem {
margin-bottom: 15px;
@include breakpoint-down('deskL') {
margin-bottom: 16px;
}
@include breakpoint-down('tabL') {
margin-bottom: 11px;
}
@include breakpoint-down('tabM') {
margin-bottom: 17px;
}
&:last-child {
margin-bottom: 0;
}
:global(.button) {
width: 100%;
font-size: 30px;
line-height: 33px;
@include breakpoint-down('deskL') {
font-size: 18px;
line-height: 19.8px;
}
@include breakpoint-down('tabL') {
height: 54px;
}
@include breakpoint-down('tabM') {
height: 45px;
font-size: 14px;
line-height: 15.4px;
}
}
:global(.checkbox .checkboxPlaceholder ) {
font-size: 21px;
line-height: 28px;
@include breakpoint-down('deskL') {
font-size: 14px;
line-height: 19.6px;
}
@include breakpoint-down('tabL') {
font-size: 10px;
line-height: 12px;
}
@include breakpoint-down('tabM') {
font-size: 12px;
line-height: 14.4px;
}
}
:global(.checkbox .checkboxContainer) {
align-items: center;
gap: 25px;
padding-top: 15px;
@include breakpoint-down('deskL') {
padding-top: 12px;
min-height: 47px;
}
@include breakpoint-down('tabL') {
min-height: 36px;
padding-top: 9px;
gap: 22px;
}
@include breakpoint-down('tabM') {
min-height: 55px;
padding-top: 14px;
align-items: start;
}
}
}
}
:global(.form__form .input .inputInput, body .form__form .textarea.bordered .textareaInput) {
font-size: 24px;
line-height: 125%;
border-radius: 12px !important;
background: rgba(241, 241, 241, 1) !important;
@include breakpoint-down('deskL') {
padding: 14px 68px 8px 24px !important;
font-size: 18px;
line-height: 140%;
}
@include breakpoint-down('deskS') {
font-size: 16px;
line-height: 100%;
}
@include breakpoint-down('tabM') {
padding: 14px 68px 5px 10px !important;
font-size: 12px;
line-height: 134% !important;
}
}
:global(.form__form .input .inputPlaceholder, .form__form .textarea.bordered .textareaPlaceholder) {
font-size: 24px;
line-height: 125%;
@include breakpoint-down('deskL') {
@include body;
line-height: 140%;
}
@include breakpoint-down('deskS') {
font-size: 16px;
line-height: 100%;
}
@include breakpoint-down('tabM') {
font-size: 12px;
line-height: 134%;
}
}
:global(body .form__form .textareaInput, body .form__form .textarea.bordered .textareaInput) {
height: 100px;
@include breakpoint-down('tabL') {
height: 88px;
}
@include breakpoint-down('tabM') {
height: 58px;
}
}
:global(body .form__form .iti .iti__selected-flag) {
border-radius: 12px;
gap: 10px;
padding: 0 16px;
justify-content: center;
background: rgba(241, 241, 241, 1) !important;
@include breakpoint-down('deskL') {
gap: 7px;
}
}
:global(body .form__form .iti .iti__flag-container) {
width: 127px !important;
@include breakpoint-down('deskL') {
width: 104px !important;
}
@include breakpoint-down('tabM') {
width: 70px !important;
}
}
:global(body .form__form .input.bordered .iti .inputInput) {
width: calc(100% - 137px) !important;
@include breakpoint-down('deskL') {
width: calc(100% - 114px) !important;
}
@include breakpoint-down('tabM') {
width: calc(100% - 80px) !important;
}
}
:global(body .form__form .input.bordered .iti + .inputPlaceholder) {
left: 160px !important;
@include breakpoint-down('deskL') {
left: 138px !important;
}
@include breakpoint-down('tabM') {
left: 94px !important;
}
}
:global(body .form__form .input.bordered .iti .iti__arrow) {
display: none;
}
:global(body .form__form .iti .iti__selected-dial-code) {
min-width: fit-content;
width: fit-content;
}
:global(body .form__form .iti .iti__flag) {
@include breakpoint-down('deskL') {
transform: scale(0.7);
margin-left: -5px;
}
}
</style>