146 lines
4.8 KiB
TypeScript
146 lines
4.8 KiB
TypeScript
import { useState, useEffect } from 'react';
|
|
import { IPaywallProduct } from "@/api/resources/Paywall";
|
|
import { generateRealisticEmail } from "@/services/random-value/emailGenerator";
|
|
import { useTranslations } from "@/hooks/translations";
|
|
import { ELocalesPlacement } from "@/locales";
|
|
|
|
interface DisplayEmail {
|
|
email: string;
|
|
price: number;
|
|
id: number;
|
|
willBeRemoved: boolean;
|
|
}
|
|
|
|
interface EmailsToDelete {
|
|
emails: DisplayEmail[];
|
|
deleteAt: number;
|
|
markAt: number;
|
|
marked: boolean;
|
|
}
|
|
|
|
export const useEmailsGeneration = (products: Array<IPaywallProduct & { weight: number }>) => {
|
|
const { translate } = useTranslations(ELocalesPlacement.EmailGenerator);
|
|
const [displayEmails, setDisplayEmails] = useState<DisplayEmail[]>([]);
|
|
const [countBoughtEmails, setCountBoughtEmails] = useState(758);
|
|
const [emailsToDeleteQueue, setEmailsToDeleteQueue] = useState<EmailsToDelete[]>([]);
|
|
|
|
const minEmails = 1;
|
|
const maxEmails = 5;
|
|
|
|
const getRandomProduct = () => {
|
|
const totalWeight = products.reduce((sum, product) => sum + (product.weight || 1), 0);
|
|
let random = Math.random() * totalWeight;
|
|
|
|
for (const product of products) {
|
|
random -= (product.weight || 1);
|
|
if (random <= 0) return product;
|
|
}
|
|
return products[0];
|
|
}
|
|
|
|
const createEmail = () => {
|
|
const product = getRandomProduct();
|
|
return {
|
|
email: generateRealisticEmail(
|
|
translate("firstNames").split(",") || [],
|
|
translate("lastNames").split(",") || [],
|
|
translate("domains").split(",") || []
|
|
),
|
|
price: (product.trialPrice || 0) / 100,
|
|
id: Date.now() + Math.random(),
|
|
willBeRemoved: false
|
|
};
|
|
}
|
|
|
|
// creating emails
|
|
useEffect(() => {
|
|
if (!products?.length) return;
|
|
addEmails(3);
|
|
return () => setDisplayEmails([]);
|
|
}, [products]);
|
|
|
|
const addEmails = (countEmails?: number) => {
|
|
const addEmailsTimeout = 3000 + Math.random() * 2000;
|
|
|
|
const count = !!countEmails ? countEmails : Math.random() < 0.6 ? 1 : 2;
|
|
const _newEmails = Array(count).fill(null).map(createEmail);
|
|
|
|
setDisplayEmails(prev => {
|
|
const updatedEmails = [...prev, ..._newEmails].slice(-maxEmails);
|
|
|
|
if (updatedEmails.length < minEmails) {
|
|
const additionalCount = minEmails - updatedEmails.length;
|
|
const additionalEmails = Array(additionalCount).fill(null).map(createEmail);
|
|
return [...updatedEmails, ...additionalEmails];
|
|
}
|
|
|
|
return updatedEmails;
|
|
});
|
|
|
|
const now = Date.now();
|
|
setEmailsToDeleteQueue(prev => [...prev, ..._newEmails.map((value) => {
|
|
const deleteTime = 3000 + Math.random() * 10000;
|
|
return {
|
|
emails: [value],
|
|
deleteAt: now + deleteTime,
|
|
markAt: now + deleteTime - 1500,
|
|
marked: false
|
|
}
|
|
})]);
|
|
|
|
const timeoutAddEmails = setTimeout(() => {
|
|
addEmails();
|
|
clearTimeout(timeoutAddEmails);
|
|
}, addEmailsTimeout);
|
|
}
|
|
|
|
useEffect(() => {
|
|
if (emailsToDeleteQueue.length === 0) return;
|
|
|
|
const checkQueue = () => {
|
|
const now = Date.now();
|
|
|
|
setEmailsToDeleteQueue(prev => {
|
|
const updatedQueue = [...prev];
|
|
let hasChanges = false;
|
|
|
|
updatedQueue.forEach(item => {
|
|
if (displayEmails.length <= minEmails) return;
|
|
if (!item.marked && now >= item.markAt) {
|
|
markEmails(item.emails);
|
|
item.marked = true;
|
|
hasChanges = true;
|
|
}
|
|
if (now >= item.deleteAt) {
|
|
deleteEmails(item.emails);
|
|
hasChanges = true;
|
|
}
|
|
});
|
|
|
|
return hasChanges ? updatedQueue.filter(item => now < item.deleteAt) : updatedQueue;
|
|
});
|
|
};
|
|
|
|
const interval = setInterval(checkQueue, 100);
|
|
return () => clearInterval(interval);
|
|
}, [emailsToDeleteQueue]);
|
|
|
|
const deleteEmails = (emailsToDelete: DisplayEmail[]) => {
|
|
setDisplayEmails(prev =>
|
|
prev.filter(email => !emailsToDelete.some(e => e.id === email.id))
|
|
);
|
|
setCountBoughtEmails(prev => prev + emailsToDelete.length);
|
|
}
|
|
|
|
const markEmails = (emailsToMark: DisplayEmail[]) => {
|
|
setDisplayEmails(prev =>
|
|
prev.map(email =>
|
|
emailsToMark.some(e => e.id === email.id)
|
|
? { ...email, willBeRemoved: true }
|
|
: email
|
|
)
|
|
);
|
|
}
|
|
|
|
return { displayEmails, countBoughtEmails };
|
|
}; |