File: //var/www/quadcode.com/src/components/popup/PopupForm.svelte
<script lang="ts">
import InputField from '../../components/form/input/InputField.svelte';
import InputFieldPhone from '../../components/form/input/InputFieldPhone.svelte';
import TextareaField from '../../components/form/input/TextareaField.svelte';
import CheckboxField from '../../components/form/input/CheckboxField.svelte';
import closeIcon from '../../assets/icons/close.svg';
import Button from '../../components/button/Button.svelte';
import Recaptcha from '../../components/form/input/Recaptcha.svelte';
import Message from '../../components/form/message/Message.svelte';
import { browser } from '$app/environment';
import type { IForm } from '$type/form';
import Validation from '$utils/Validation';
import { popupForm } from '../../store';
import createEvent from '$utils/createEvents';
import { localeLink, t } from '$lib/translations';
import { getCookieByName } from '$utils/cookie';
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);
}
let recaptcha: { getResponse: () => string; reset: () => void };
const formState: IForm = {
loading: false,
error: false,
data: {
name: '',
email: '',
phone: '',
text: '',
initialInvestment: '',
agreement: false,
roistatId,
},
response: {},
status: 0,
};
createEvent({ event: 'saas_form_opening' });
const sendForm = async () => {
formState.loading = true;
const code = document.querySelector('.iti__selected-dial-code');
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;
}
formState.data.token = recaptcha?.getResponse() ?? '';
formState.data['landing_url'] = window.location.host + window.location.pathname;
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/send`, {
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;
recaptcha?.reset();
});
};
const clickSendMore = () => {
formState.data = {};
formState.response = {};
formState.status = 0;
popupForm.set(false);
recaptcha?.reset();
};
$: showMessage = formState.response?.status === 'ok' || [500, 502, 429].includes(formState.status);
</script>
<div class="popupForm">
<div class="container">
<div class="block-feedback">
<div class="block-feedback__wrapper" on:click={() => popupForm.set(false)}>
<div class="block-feedback__form" on:click|stopPropagation class:show-message={showMessage}>
{#if !showMessage}
<div class="test">
<button
class="block-feedback__close"
on:click={() => popupForm.set(false)}
aria-label="Close"
>
<img src={closeIcon} alt="Close" />
</button>
<p class="block-feedback__formTitle">{$t('Leave your request')}</p>
<p class="block-feedback__formSubtitle">{$t('You are on the right path to creating your own broker')}</p>
<div class="block-feedback__formItems">
<div class="block-feedback__formItem">
<InputField
className="popup-form-input"
placeholder={$t('Full name')}
name="name"
error={formState.response.name}
value={String(formState.data.name || '')}
onChange={(e) => {
formState.data.name = e.currentTarget.value;
Validation({ name: 'name', value: e.currentTarget.value, formState });
}}
/>
</div>
<div class="block-feedback__formItem">
<InputField
className="popup-form-input"
placeholder={$t('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="block-feedback__formItem">
<InputFieldPhone
className="popup-form-input phone-input"
placeholder={$t('Phone')}
name="phone"
error={formState.response.phone}
value={String(formState.data.phone || '')}
useFullscreenPopup={false}
onChange={(e) => {
formState.data.phone = e.currentTarget.value;
Validation({ name: 'phone', value: e.currentTarget.value, formState });
}}
/>
</div>
<div class="block-feedback__formItem">
<InputField
className="popup-form-input"
placeholder={$t('Initial investment')}
name="initialInvestment"
error={formState.response.initialInvestment}
value={String(formState.data.initialInvestment || '')}
onChange={(e) => {
formState.data.initialInvestment = e.currentTarget.value;
}}
/>
</div>
<div class="block-feedback__formItem">
<TextareaField
className="popup-form-textarea"
placeholder={$t('Message')}
name="text"
error={formState.response.text}
value={String(formState.data.text || '')}
onChange={(e) => {
formState.data.text = e.currentTarget.value;
}}
/>
</div>
<div class="block-feedback__formItem">
<CheckboxField
placeholder={`${$t('I read and agree with')} <a href="${localeLink()}/terms-and-conditions">${$t('terms and conditions')}</a> ${$t('and')} <a href="${localeLink()}/privacy-policy">${$t('privacy policy')}</a> ${$t('of this website')}`}
name="agreement"
error={formState.response.agreement}
checked={Boolean(formState.data.agreement)}
onChange={(e) => {
formState.data.agreement = e.currentTarget.checked;
Validation({ name: 'agreement', value: e.currentTarget.checked, formState });
}}
/>
</div>
<div class="block-feedback__formItem recaptcha">
<Recaptcha bind:this={recaptcha} error={formState.response.token} />
</div>
<div class="block-feedback__formItem">
<Button
text={$t('Get in touch')}
className="block-feedback__button"
onClick={sendForm}
loading={formState.loading}
/>
</div>
</div>
<p class="block-feedback__legalText">
{$t('By continuing you accept our')} <a href="{localeLink()}/terms-and-conditions">{$t('Terms & Conditions')}</a> {$t('and')} <a href="{localeLink()}/privacy-policy">{$t('Privacy policy')}</a>
</p>
</div>
{/if}
{#if formState.response?.status === 'ok'}
<Message
onClick={clickSendMore}
text={$t('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>
</div>
</div>
</div>
</div>
<style lang="scss">
@import 'src/scss/media';
@import 'src/scss/mixins';
@import 'src/scss/variables';
.popupForm {
position: fixed;
z-index: 101;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(#1B1C1D, 0.7);
overflow-y: auto;
padding: 16px 0;
overflow: hidden;
.container {
height: max-content;
position: relative;
top: 50%;
right: 16px;
transform: translateY(-50%);
margin: 0;
max-width: 100%;
@include breakpoint-down('tabL') {
top: 0;
right: 0;
transform: none;
padding: 0 16px;
}
@include breakpoint-down('mobL') {
padding: 0 12px;
}
}
&::-webkit-scrollbar {
width: 0;
opacity: 0;
display: none;
}
}
.block-feedback {
&__wrapper {
display: flex;
align-items: flex-start;
justify-content: flex-end;
max-height: 100%;
overflow-y: auto;
gap: 40px;
@include breakpoint-down('deskL') {
gap: 32px;
}
@include breakpoint-down('deskS') {
gap: 20px;
}
@include breakpoint-down('tabM') {
flex-direction: column;
gap: 34px;
justify-content: flex-start;
align-items: flex-end;
}
}
&__content {
padding-top: 30px;
width: 800px;
@include breakpoint-down('deskL') {
padding-top: 0;
width: 639px;
}
@include breakpoint-down('deskS') {
width: 100%;
max-width: 43%;
}
@include breakpoint-down('tabM') {
max-width: none;
}
}
&__contentBlock {
@include breakpoint-down('deskS') {
display: flex;
gap: 16px;
}
@include breakpoint-down('tabM') {
display: none;
}
}
&__form {
position: relative;
width: 522px;
max-height: min(992px, calc(100vh - 32px));
height: min(992px, calc(100vh - 32px));
overflow-y: auto;
overflow-x: hidden;
padding: 68px 40px 40px 40px;
border-radius: 32px;
background: #f2f5f7;
display: flex;
flex-direction: column;
scrollbar-width: none;
-ms-overflow-style: none;
&::-webkit-scrollbar {
width: 0;
height: 0;
background: transparent;
display: none;
}
@include breakpoint-down('deskL') {
width: 490px;
}
@include breakpoint-down('deskS') {
width: 100%;
max-width: 490px;
}
@media (max-width: 393px) {
padding: 68px 20px;
}
}
&__form :global(.popup-form-input .inputInput) {
background: $techWhite !important;
border: none !important;
border-radius: 16px !important;
height: 60px !important;
}
&__formItem:focus .inputPlaceholder {
font-size: 12px;
}
&__form :global(.inputContainer .inputPlaceholder) {
font-size: 16px;
line-height: 24px;
left: 16px !important;
}
&__form :global(.phone-input .inputPlaceholder) {
left: 136px !important;
}
&__form :global(.phone-input input){
width: calc(100% - 120px) !important;
}
&__form :global(.popup-form-input.phone-input .inputPlaceholder) {
font-size: 16px;
line-height: 24px;
}
&__form :global(.popup-form-textarea .textareaInput) {
background: $techWhite !important;
border: none !important;
border-radius: 16px !important;
height: 166px !important;
box-shadow: none;
}
&__form :global(.popup-form-textarea .textareaPlaceholder){
font-size: 16px ;
line-height: 24px ;
}
&__title {
@include titleXL;
max-width: 80%;
margin-bottom: 64px;
@include breakpoint-down('deskL') {
margin-bottom: 40px;
}
@include breakpoint-down('deskS') {
margin-bottom: 36px;
}
@include breakpoint-down('tabM') {
display: none;
}
> span {
color: $redPrimary;
}
}
&__grid {
display: flex;
align-items: center;
width: 100%;
max-width: 680px;
gap: 27px;
margin-bottom: 24px;
user-select: none;
@include breakpoint-down('deskL') {
margin-bottom: 16px;
}
@include breakpoint-down('deskS') {
flex-direction: column;
margin-bottom: 0;
width: max-content;
gap: 24px;
}
}
&__gridItem {
position: relative;
z-index: 1;
display: flex;
align-items: center;
justify-content: center;
flex: 1;
text-align: center;
width: 83px;
min-width: 83px;
height: 83px;
background-image: url("data:image/svg+xml,%3Csvg width='83' height='83' viewBox='0 0 83 83' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='41.5' cy='41.5' r='41.5' fill='white'/%3E%3C/svg%3E%0A");
background-repeat: no-repeat;
background-size: contain;
background-position: center;
font-family: $Inter;
font-size: 32px;
font-weight: 400;
line-height: 35px;
@include breakpoint-down('deskL') {
width: 64px;
min-width: 64px;
height: 64px;
font-size: 24px;
line-height: 26px;
}
@include breakpoint-down('deskS') {
flex: none;
width: 48px;
min-width: 48px;
height: 48px;
font-size: 21px;
line-height: 23px;
}
&:after {
content: '';
position: absolute;
top: 50%;
transform: translateY(-50%);
height: 1px;
width: 80%;
background-image: url("data:image/svg+xml,%3Csvg width='70' height='1' viewBox='0 0 70 1' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cline x1='0.5' y1='0.5' x2='69.5' y2='0.5' stroke='%23CFDAE1' stroke-linecap='round' stroke-dasharray='1 7'/%3E%3C/svg%3E%0A");
background-size: contain;
z-index: -1;
left: 100%;
@include breakpoint-down('deskL') {
width: 80%;
left: 85%;
background-image: url("data:image/svg+xml,%3Csvg width='68' height='1' viewBox='0 0 68 1' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cline x1='0.5' y1='0.5' x2='67.5' y2='0.500006' stroke='%23CFDAE1' stroke-linecap='round' stroke-dasharray='1 7'/%3E%3C/svg%3E%0A");
}
}
&:first-of-type {
margin-right: 34px;
width: 115px;
min-width: 115px;
height: 115px;
background-image: url("data:image/svg+xml,%3Csvg width='116' height='115' viewBox='0 0 116 115' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='58' cy='57.5' r='57.5' fill='url(%23paint0_linear_10220_19321)'/%3E%3Cdefs%3E%3ClinearGradient id='paint0_linear_10220_19321' x1='58' y1='0' x2='58' y2='115' gradientUnits='userSpaceOnUse'%3E%3Cstop stop-color='%2340454E'/%3E%3Cstop offset='1' stop-color='%23313840'/%3E%3C/linearGradient%3E%3C/defs%3E%3C/svg%3E%0A");
color: $techWhite;
font-size: 48px;
font-weight: 500;
line-height: 53px;
@include breakpoint-down('deskL') {
width: 80px;
min-width: 80px;
height: 80px;
font-size: 36px;
line-height: 40px;
margin-left: 10px;
margin-right: -4px;
}
@include breakpoint-down('deskS') {
margin-left: 0;
margin-right: 0;
width: 64px;
min-width: 64px;
height: 64px;
font-size: 28px;
line-height: 30px;
}
&:after {
@include breakpoint-down('deskL') {
left: 90%;
}
}
}
&:last-of-type {
&:after {
display: none;
}
}
}
&__text {
display: flex;
align-items: flex-start;
width: 100%;
max-width: 680px;
gap: 27px;
@include breakpoint-down('deskS') {
flex-direction: column;
width: calc((100% - 64px));
gap: 24px;
}
}
&__textItem {
@include smallDefault;
flex: 1;
text-align: center;
@include breakpoint-down('deskS') {
display: flex;
align-items: center;
text-align: left;
flex: none;
min-height: 48px;
}
&:first-of-type {
@include baseTitle;
min-width: 115px;
margin-right: 34px;
@include breakpoint-down('deskL') {
margin-left: 3px;
margin-right: -8px;
}
@include breakpoint-down('deskS') {
min-height: 64px;
min-width: auto;
margin-left: 0;
margin-right: 0;
}
}
}
& :global(.block-feedback__back) {
margin-bottom: 40px;
@include breakpoint-down('tabM') {
margin-bottom: 0;
}
}
&__close {
position: absolute;
top: 16px;
right: 16px;
background: #eaecef;
border: none;
border-radius: 48px;
cursor: pointer;
padding: 12px 16px;
display: flex;
align-items: center;
justify-content: center;
z-index: 100;
transition: opacity 0.2s ease;
width: auto;
height: auto;
img {
width: 12px;
height: 12px;
display: block;
filter: brightness(0) saturate(100%) invert(11%) sepia(0%) saturate(0%) hue-rotate(0deg) brightness(95%) contrast(100%);
}
&:hover {
opacity: 0.7;
}
@include breakpoint-down('deskS') {
top: 16px;
right: 16px;
}
}
&__formTitle {
font-size: 32px;
line-height: 40px;
margin-bottom: 12px;
color: #1B1C1D;
@media (max-width: 1024px) {
font-size: 28px;
line-height: 36px;
}
@media (max-width: 720px) {
font-size: 24px;
line-height: 28px;
}
@media (max-width: 393px) {
font-size: 20px;
line-height: 26px;
margin-bottom: 8px;
}
}
&__formSubtitle {
font-size: 14px;
line-height: 20px;
margin-bottom: 40px;
color: #7D8387;
@media (max-width: 1024px) {
margin-bottom: 32px;
}
@media (max-width: 393px) {
margin-bottom: 24px;
}
}
&__legalText {
color: #7D8387;
font-size: 14px;
line-height: 20px;
max-width: 390px;
margin-top:auto;
a {
color: #1B1C1D;
border-bottom: 1px solid #D4D8DB;
text-decoration: none;
}
}
&__formItems {
display: flex;
flex-direction: column;
gap: 12px;
@include breakpoint-down('deskS') {
gap: 24px;
}
}
&__formItem {
width: 100%;
& :global(.checkboxContainer) {
@include breakpoint-down('deskS') {
margin-top: -16px;
}
}
&.recaptcha {
display: flex;
justify-content: center;
margin-top: 24px;
margin-bottom: 12px;
transform: scale(1.35);
@media (max-width: 720px) {
transform: scale(1.6);
}
@media (max-width: 480px) {
transform: scale(1.45);
}
@media (max-width: 393px) {
transform: scale(1.3);
}
}
&:has(.block-feedback__button) {
margin-top: 12px;
margin-bottom: 70px;
}
}
& :global(.block-feedback__button) {
font-size: 16px;
line-height: 24px;
width: 100%;
padding: 14px 0;
background-color: #FF282B;
margin-top: 0;
&:hover{
background-color: #E60019;
}
&:active{
background-color: #C70214;
}
}
}
.back {
display: flex;
align-items: center;
width: max-content;
gap: 10px;
cursor: pointer;
@include breakpoint-down('deskS') {
gap: 8px;
}
&__icon {
width: 34px;
height: 19px;
}
&__text {
@include baseTitle;
}
}
:global(.block-feedback__title span) {
color: $redPrimary;
}
:global(.block-feedback__form .iti) {
width: 100% !important;
}
:global(.block-feedback__form .iti .iti__selected-flag) {
border-radius: 16px;
padding: 10px 16px;
border: none;
background: white !important;
}
.block-feedback__form {
:global(.popup-form-input.focus .inputPlaceholder),
:global(.popup-form-input.value .inputPlaceholder) {
font-size: 12px !important;
line-height: 16px !important;
}
:global(.popup-form-input.phone-input.focus .inputPlaceholder),
:global(.popup-form-input.phone-input.value .inputPlaceholder) {
font-size: 12px !important;
line-height: 16px !important;
}
:global(.popup-form-textarea.focus .textareaPlaceholder),
:global(.popup-form-textarea.value .textareaPlaceholder) {
font-size: 12px !important;
line-height: 16px !important;
}
:global(.iti__flag-container){
width: 112px;
}
}
</style>