// app.js - Главный файл приложения
class GuarantorApp {
constructor() {
this.init();
}
init() {
this.initComponents();
this.initAnalytics();
this.initServiceWorker();
this.initPerformanceMonitoring();
this.initAIFeatures();
}
initComponents() {
// Инициализация всех компонентов
this.components = {
hero: new HeroSection(),
problems: new ProblemsSection(),
howItWorks: new HowItWorks(),
targetAudience: new TargetAudience(),
security: new SecuritySection(),
dealTypes: new DealTypes(),
dealProcess: new DealProcess(),
cryptocurrencies: new Cryptocurrencies(),
advantages: new Advantages(),
cases: new CasesSection(),
reviews: new ReviewsSection(),
partners: new PartnersSection(),
faq: new FAQSection(),
calculator: new CalculatorSection(),
team: new TeamSection(),
blog: new BlogSection(),
verification: new VerificationSection(),
arbitration: new ArbitrationSection(),
mobile: new MobileSection(),
affiliate: new AffiliateSection(),
legal: new LegalSection(),
tech: new TechSection(),
registration: new RegistrationSection(),
cta: new CTASection(),
footer: new FooterSection(),
modals: new ModalsManager(),
floating: new FloatingElements()
};
}
initAnalytics() {
// Инициализация аналитики
this.analytics = {
google: this.initGoogleAnalytics(),
yandex: this.initYandexMetrica(),
hotjar: this.initHotjar(),
amplitude: this.initAmplitude(),
mixpanel: this.initMixpanel()
};
}
initServiceWorker() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
console.log('ServiceWorker зарегистрирован');
this.serviceWorker = registration;
})
.catch(error => {
console.error('Ошибка регистрации ServiceWorker:', error);
});
}
}
initPerformanceMonitoring() {
// Мониторинг Web Vitals
if ('web-vitals' in window) {
webVitals.getCLS(this.logCLS);
webVitals.getFID(this.logFID);
webVitals.getLCP(this.logLCP);
webVitals.getFCP(this.logFCP);
webVitals.getTTFB(this.logTTFB);
}
// Мониторинг ошибок
window.addEventListener('error', this.handleError);
window.addEventListener('unhandledrejection', this.handlePromiseRejection);
// Мониторинг производительности
this.performanceObserver = new PerformanceObserver((list) => {
list.getEntries().forEach(entry => {
this.logPerformanceEntry(entry);
});
});
this.performanceObserver.observe({ entryTypes: ['navigation', 'resource', 'paint'] });
}
initAIFeatures() {
// Инициализация AI функций
this.ai = {
riskAnalyzer: new AIRiskAnalyzer(),
recommendationEngine: new AIRecommendationEngine(),
chatAssistant: new AIChatAssistant(),
fraudDetection: new AIFraudDetection(),
personalization: new AIPersonalization()
};
}
// Методы логирования
logCLS(metric) {
console.log('CLS:', metric.value);
this.sendAnalytics('web-vitals', 'CLS', metric.value);
}
logFID(metric) {
console.log('FID:', metric.value);
this.sendAnalytics('web-vitals', 'FID', metric.value);
}
logLCP(metric) {
console.log('LCP:', metric.value);
this.sendAnalytics('web-vitals', 'LCP', metric.value);
}
logFCP(metric) {
console.log('FCP:', metric.value);
this.sendAnalytics('web-vitals', 'FCP', metric.value);
}
logTTFB(metric) {
console.log('TTFB:', metric.value);
this.sendAnalytics('web-vitals', 'TTFB', metric.value);
}
handleError(event) {
const error = {
message: event.message,
filename: event.filename,
lineno: event.lineno,
colno: event.colno,
error: event.error?.stack
};
console.error('JavaScript Error:', error);
this.sendAnalytics('error', 'js-error', error);
}
handlePromiseRejection(event) {
console.error('Unhandled Promise Rejection:', event.reason);
this.sendAnalytics('error', 'promise-rejection', event.reason);
}
logPerformanceEntry(entry) {
const data = {
name: entry.name,
type: entry.entryType,
startTime: entry.startTime,
duration: entry.duration,
...entry.toJSON()
};
console.log('Performance Entry:', data);
// Отправка в аналитику для важных метрик
if (entry.entryType === 'navigation') {
this.sendAnalytics('performance', 'navigation', data);
}
}
sendAnalytics(category, action, value) {
// Отправка в Google Analytics
if (typeof gtag !== 'undefined') {
gtag('event', action, {
event_category: category,
event_label: JSON.stringify(value),
value: typeof value === 'number' ? value : 1
});
}
// Отправка в Yandex.Metrica
if (typeof ym !== 'undefined') {
ym(12345678, 'reachGoal', `${category}_${action}`);
}
// Отправка на сервер
fetch('/api/analytics', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
category,
action,
value,
timestamp: Date.now(),
userAgent: navigator.userAgent,
url: window.location.href
})
});
}
// Методы работы с пользователем
trackUserBehavior(action, data = {}) {
const behavior = {
action,
data,
timestamp: Date.now(),
sessionId: this.getSessionId(),
userId: this.getUserId()
};
localStorage.setItem(`behavior_${Date.now()}`, JSON.stringify(behavior));
this.sendAnalytics('user-behavior', action, behavior);
}
getSessionId() {
let sessionId = sessionStorage.getItem('sessionId');
if (!sessionId) {
sessionId = 'session_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
sessionStorage.setItem('sessionId', sessionId);
}
return sessionId;
}
getUserId() {
return localStorage.getItem('userId') || 'anonymous';
}
// Методы работы с сделками
createDeal(dealData) {
return new Promise((resolve, reject) => {
// Валидация данных
if (!this.validateDealData(dealData)) {
reject(new Error('Invalid deal data'));
return;
}
// Отправка на сервер
fetch('/api/deals/create', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(dealData)
})
.then(response => response.json())
.then(data => {
if (data.success) {
this.trackUserBehavior('deal-created', dealData);
resolve(data);
} else {
reject(new Error(data.error || 'Creation failed'));
}
})
.catch(reject);
});
}
validateDealData(data) {
const requiredFields = ['type', 'amount', 'currency', 'parties'];
return requiredFields.every(field => data[field]);
}
// Методы безопасности
encryptData(data, key) {
// Использование Web Crypto API для шифрования
return crypto.subtle.encrypt(
{ name: 'AES-GCM', iv: new Uint8Array(12) },
key,
new TextEncoder().encode(JSON.stringify(data))
);
}
generateKey() {
return crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
true,
['encrypt', 'decrypt']
);
}
// Методы работы с криптовалютами
async getCryptoPrices() {
try {
const response = await fetch('https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&ids=bitcoin,ethereum,tether');
const data = await response.json();
this.cachePrices(data);
return data;
} catch (error) {
// Возвращаем кэшированные данные
return this.getCachedPrices();
}
}
cachePrices(prices) {
const cache = {
data: prices,
timestamp: Date.now()
};
localStorage.setItem('cryptoPrices', JSON.stringify(cache));
}
getCachedPrices() {
const cached = localStorage.getItem('cryptoPrices');
if (cached) {
const { data, timestamp } = JSON.parse(cached);
// Используем кэш если ему меньше 5 минут
if (Date.now() - timestamp < 5 * 60 * 1000) {
return data;
}
}
return null;
}
// Методы персонализации
personalizeContent(userPreferences) {
// Анализ предпочтений пользователя
const preferences = userPreferences || this.getUserPreferences();
// Персонализация контента
this.components.forEach(component => {
if (component.personalize) {
component.personalize(preferences);
}
});
// Персонализация рекомендаций
this.ai.recommendationEngine.generateRecommendations(preferences);
}
getUserPreferences() {
const prefs = localStorage.getItem('userPreferences');
return prefs ? JSON.parse(prefs) : {
interests: [],
dealTypes: [],
riskTolerance: 'medium',
experienceLevel: 'beginner'
};
}
// Методы для A/B тестирования
runABTest(testName, variants) {
const testId = `ab_test_${testName}`;
let variant = localStorage.getItem(testId);
if (!variant) {
// Случайное назначение варианта
variant = variants[Math.floor(Math.random() * variants.length)];
localStorage.setItem(testId, variant);
}
return variant;
}
trackABTestConversion(testName, variant) {
this.sendAnalytics('ab-test', testName, {
variant,
converted: true,
timestamp: Date.now()
});
}
// Методы для геймификации
awardAchievement(achievementId) {
const achievements = JSON.parse(localStorage.getItem('achievements') || '[]');
if (!achievements.includes(achievementId)) {
achievements.push(achievementId);
localStorage.setItem('achievements', JSON.stringify(achievements));
// Показать уведомление
this.showAchievementNotification(achievementId);
// Отправить в аналитику
this.sendAnalytics('achievement', 'unlocked', achievementId);
}
}
showAchievementNotification(achievementId) {
const achievements = {
'first_deal': {
title: 'Первая сделка!',
description: 'Вы успешно завершили свою первую сделку',
icon: '????'
},
'large_deal': {
title: 'Крупная сделка',
description: 'Завершена сделка на сумму более $10,000',
icon: '????'
},
'quick_deal': {
title: 'Скоростная сделка',
description: 'Сделка завершена менее чем за 1 час',
icon: '⚡'
}
};
const achievement = achievements[achievementId];
if (achievement) {
this.showNotification(achievement);
}
}
showNotification(data) {
const notification = document.createElement('div');
notification.className = 'achievement-notification';
notification.innerHTML = `
${data.icon}
${data.title}
${data.description}
`;
document.body.appendChild(notification);
// Анимация появления
gsap.from(notification, {
x: 100,
opacity: 0,
duration: 0.5,
ease: "back.out(1.7)"
});
// Автоматическое скрытие
setTimeout(() => {
notification.remove();
}, 5000);
// Закрытие по клику
notification.querySelector('.close-notification').addEventListener('click', () => {
notification.remove();
});
}
// Методы для офлайн-работы
setupOfflineSupport() {
// Кэширование важных данных
this.cacheCriticalData();
// Обработка офлайн-состояния
window.addEventListener('online', this.handleOnline);
window.addEventListener('offline', this.handleOffline);
}
handleOnline() {
console.log('Приложение онлайн');
// Синхронизация данных
this.syncOfflineData();
}
handleOffline() {
console.log('Приложение офлайн');
// Показать уведомление
this.showOfflineNotification();
}
syncOfflineData() {
// Синхронизация данных, накопленных в офлайне
const offlineActions = JSON.parse(localStorage.getItem('offlineActions') || '[]');
offlineActions.forEach(action => {
this.performAction(action);
});
localStorage.removeItem('offlineActions');
}
// Методы для push-уведомлений
requestNotificationPermission() {
if ('Notification' in window && Notification.permission === 'default') {
Notification.requestPermission().then(permission => {
if (permission === 'granted') {
this.setupPushNotifications();
}
});
}
}
setupPushNotifications() {
if ('serviceWorker' in navigator && 'PushManager' in window) {
navigator.serviceWorker.ready.then(registration => {
registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: this.urlBase64ToUint8Array('YOUR_PUBLIC_VAPID_KEY')
})
.then(subscription => {
this.saveSubscription(subscription);
})
.catch(error => {
console.error('Ошибка подписки на push:', error);
});
});
}
}
urlBase64ToUint8Array(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
saveSubscription(subscription) {
fetch('/api/push/subscribe', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(subscription)
});
}
// Методы для темной темы
initThemeSwitcher() {
const theme = localStorage.getItem('theme') ||
(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
this.setTheme(theme);
// Слушатель изменения системной темы
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
if (!localStorage.getItem('theme')) {
this.setTheme(e.matches ? 'dark' : 'light');
}
});
}
setTheme(theme) {
document.documentElement.setAttribute('data-theme', theme);
localStorage.setItem('theme', theme);
}
toggleTheme() {
const currentTheme = document.documentElement.getAttribute('data-theme');
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
this.setTheme(newTheme);
}
// Методы для локализации
initLocalization() {
const lang = localStorage.getItem('language') ||
navigator.language.split('-')[0] ||
'ru';
this.setLanguage(lang);
}
setLanguage(lang) {
document.documentElement.lang = lang;
localStorage.setItem('language', lang);
// Загрузка переводов
this.loadTranslations(lang);
}
async loadTranslations(lang) {
try {
const response = await fetch(`/locales/${lang}.json`);
const translations = await response.json();
this.applyTranslations(translations);
} catch (error) {
console.error('Ошибка загрузки переводов:', error);
}
}
applyTranslations(translations) {
// Применение переводов ко всем элементам с data-i18n
document.querySelectorAll('[data-i18n]').forEach(element => {
const key = element.getAttribute('data-i18n');
if (translations[key]) {
element.textContent = translations[key];
}
});
}
// Методы для доступности (a11y)
initAccessibility() {
// Управление фокусом
this.setupFocusManagement();
// Поддержка клавиатуры
this.setupKeyboardNavigation();
// ARIA атрибуты
this.setupARIA();
// Увеличение текста
this.setupTextResizing();
}
setupFocusManagement() {
// Сохранение фокуса в модальных окнах
document.addEventListener('keydown', (e) => {
if (e.key === 'Tab' && this.activeModal) {
this.trapFocus(this.activeModal, e);
}
});
}
trapFocus(element, event) {
const focusable = element.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
if (focusable.length === 0) return;
const first = focusable[0];
const last = focusable[focusable.length - 1];
if (event.shiftKey) {
if (document.activeElement === first) {
last.focus();
event.preventDefault();
}
} else {
if (document.activeElement === last) {
first.focus();
event.preventDefault();
}
}
}
setupKeyboardNavigation() {
document.addEventListener('keydown', (e) => {
// Закрытие модалок по ESC
if (e.key === 'Escape' && this.activeModal) {
this.closeModal(this.activeModal);
}
// Навигация по табам
if (e.key === 'ArrowRight' || e.key === 'ArrowLeft') {
this.handleTabNavigation(e);
}
});
}
setupARIA() {
// Динамическое обновление ARIA атрибутов
this.updateLiveRegions();
// Управление состоянием элементов
this.setupARIAStates();
}
setupTextResizing() {
// Кнопки увеличения/уменьшения текста
const textSizeControls = document.createElement('div');
textSizeControls.className = 'text-size-controls';
textSizeControls.innerHTML = `
`;
document.body.appendChild(textSizeControls);
// Обработчики
document.getElementById('increaseTextSize').addEventListener('click', () => {
this.changeTextSize(1);
});
document.getElementById('decreaseTextSize').addEventListener('click', () => {
this.changeTextSize(-1);
});
document.getElementById('resetTextSize').addEventListener('click', () => {
this.resetTextSize();
});
}
changeTextSize(delta) {
const currentSize = parseFloat(getComputedStyle(document.documentElement).fontSize);
const newSize = currentSize + delta;
document.documentElement.style.fontSize = `${newSize}px`;
localStorage.setItem('textSize', newSize);
}
resetTextSize() {
document.documentElement.style.fontSize = '';
localStorage.removeItem('textSize');
}
// Метод запуска приложения
start() {
console.log('Guarantor.Su приложение запущено');
// Запуск всех систем
this.setupOfflineSupport();
this.requestNotificationPermission();
this.initThemeSwitcher();
this.initLocalization();
this.initAccessibility();
// Отслеживание производительности
this.trackPerformance();
// Запуск AI систем
this.ai.riskAnalyzer.start();
this.ai.recommendationEngine.start();
// Инициализация пользовательской сессии
this.initUserSession();
}
initUserSession() {
const sessionData = {
startTime: Date.now(),
referrer: document.referrer,
landingPage: window.location.pathname,
utmParams: this.getUTMParameters(),
deviceInfo: this.getDeviceInfo()
};
sessionStorage.setItem('sessionData', JSON.stringify(sessionData));
this.sendAnalytics('session', 'start', sessionData);
}
getUTMParameters() {
const params = new URLSearchParams(window.location.search);
const utm = {};
['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'].forEach(param => {
if (params.has(param)) {
utm[param] = params.get(param);
}
});
return utm;
}
getDeviceInfo() {
return {
userAgent: navigator.userAgent,
platform: navigator.platform,
language: navigator.language,
screen: {
width: window.screen.width,
height: window.screen.height,
colorDepth: window.screen.colorDepth
},
connection: navigator.connection ? {
effectiveType: navigator.connection.effectiveType,
downlink: navigator.connection.downlink,
rtt: navigator.connection.rtt
} : null
};
}
trackPerformance() {
// Отслеживание метрик производительности
const perfData = performance.getEntriesByType('navigation')[0];
if (perfData) {
const metrics = {
dns: perfData.domainLookupEnd - perfData.domainLookupStart,
tcp: perfData.connectEnd - perfData.connectStart,
ssl: perfData.connectEnd - perfData.secureConnectionStart,
ttfb: perfData.responseStart - perfData.requestStart,
download: perfData.responseEnd - perfData.responseStart,
domReady: perfData.domContentLoadedEventEnd - perfData.domContentLoadedEventStart,
pageLoad: perfData.loadEventEnd - perfData.loadEventStart
};
this.sendAnalytics('performance', 'page-load', metrics);
}
}
// Метод для деструктора
destroy() {
// Очистка всех слушателей событий
this.components.forEach(component => {
if (component.destroy) {
component.destroy();
}
});
// Отключение Service Worker
if (this.serviceWorker) {
this.serviceWorker.unregister();
}
// Очистка анимаций
gsap.globalTimeline.clear();
console.log('Приложение остановлено');
}
}
// Экспорт приложения
window.GuarantorApp = GuarantorApp;
// Запуск приложения при загрузке страницы
document.addEventListener('DOMContentLoaded', () => {
window.app = new GuarantorApp();
window.app.start();
});
// Глобальные обработчики ошибок
window.addEventListener('error', (event) => {
if (window.app) {
window.app.handleError(event);
}
});
window.addEventListener('unhandledrejection', (event) => {
if (window.app) {
window.app.handlePromiseRejection(event);
}
});