promo! react

This commit is contained in:
Zakhar 2026-08-28 09:41:34 +03:00
parent 8c5d86c9ab
commit 8526e66f5c
4 changed files with 142 additions and 21 deletions

View File

@ -28,18 +28,19 @@ export async function loadInitialData(): Promise<InitialData> {
return retryResponse.json();
}
// Handle 403 or need_refresh cases
if (response.status === 403 || data.error_message === 'need_refresh') {
await refreshToken();
const retryResponse = await fetch(apiUrl('/api/promo/get_initial_data'), {
credentials: 'include',
});
return retryResponse.json();
}
// Success case
return data;
} catch {
} catch (error) {
console.error('Error in loadInitialData:', error);
return fallbackInitialData;
}
}
@ -116,4 +117,4 @@ const fallbackInitialData: InitialData = {
days: 7,
excess: 0,
precision: 0,
}
};

View File

@ -15,6 +15,7 @@ interface AccordionProps {
}
export function Accordion({
id,
title,
description,
icon,
@ -22,10 +23,10 @@ export function Accordion({
isHighlighted = true,
onToggle,
children,
}: AccordionProps) {
}: AccordionProps) {
return (
<Item>
<Header type="button" onClick={onToggle}>
<Header onClick={onToggle}>
<HeaderLeft>
<IconCircle $highlighted={isHighlighted}>
{icon ?? <HeartIcon />}
@ -58,7 +59,7 @@ const Item = styled.div`
}
`;
const Header = styled.button`
const Header = styled.div`
width: 100%;
display: flex;
align-items: center;

View File

@ -11,6 +11,103 @@ interface UseCartPollingParams {
setDisplayText: Dispatch<SetStateAction<string>>;
}
let missing_scenarios = [
[
[10_000, 'Ищем Брока...'],
[30_000, 'Брок сбежал из супермаркета...'],
[30_000, 'Мы всё ещё пытаемся его найти...'],
[10_000, 'Может быть он в колбасном отделе?'],
[10_000, 'Или в своём любимом?'],
[10_000, 'Какой у Брока любимый отдел?'],
[10_000, 'Если это прятки, то я проиграл, выходи'],
[15_000, 'Я сдаюсь, перезагрузите страницу?'],
],
[
[10_000, 'Брок у полки с соком...'],
[20_000, 'Он выбирает апельсиновый...'],
[15_000, 'Вспомнил, что любит яблочный...'],
[25_000, 'Теперь сравнивает состав...'],
[20_000, 'Сока нет, есть нектар...'],
[15_000, 'Брок возмущён...'],
[20_000, 'Он уходит с водой...'],
[10_000, 'Классика. Перезагрузите страницу?']
],
[
[10_000, 'Брок в молочном отделе...'],
[10_000, 'Ищет кефир 1%...'],
[10_000, 'Нашёл, но срок годности...'],
[10_000, 'Завтра. Брок не рискует...'],
[10_000, 'Берёт 2,5%...'],
[10_000, 'Потом ставит обратно...'],
[10_000, 'Пробует на ощупь ряженку...'],
[10_000, 'Это надолго. Перезагрузите страницу?']
],
[
[10_000, 'Брок в отделе замороженных продуктов...'],
[15_000, 'Брок застрял в отделе заморозки. Буквально...'],
[10_000, 'Брок пытается открыть морозилку изнутри...'],
[10_000, 'Кажется, два пломбира ему мешают...'],
[10_000, 'Вызвали спасателей и сотрудника с ломом...'],
[10_000, 'Брок заявил, что без пломбира не выйдет...'],
[10_000, 'Переговоры вступили в финальную стадию...'],
[10_000, 'У Брока коробка пломбира'],
[10_000, 'Перезагрузите страницу?'],
],
[
[10_000, 'Брок увидел акцию 1+1 и теперь не может выбрать...'],
[10_000, 'Брок сказал, что ему нужно ещё пять минуточек...'],
[10_000, 'Брок увлёкся бесплатными образцами...'],
[10_000, 'Кажется, Брок уже на КСО'],
[10_000, 'Брок забыл, что он собирает корзину?'],
[10_000, 'Брок двигается к выходу с арбузом...'],
[10_000, 'Брок отвлёкся на робот-пылесос...'],
[10_000, 'Перезагрузите страницу?'],
],
[
[10_000, 'Брок встал в очередь на кассу...'],
[10_000, 'У Брока в корзине один огурец и лотерейный билет...'],
[10_000, 'Брок завис на вопросе: «Пакет нужен?»'],
[10_000, 'Брок спрашивает: «А у вас есть пакет с динозаврами?»'],
[10_000, 'Брок утверждает, что видел такие пакеты в рекламе 2007 года...'],
[10_000, 'Менеджер ищет пакеты с динозаврами на складе...'],
[10_000, 'Это надолго, нужна перезагрузка'],
],
[
[10_000, 'Брок обнаружил тележку с крутящимся передним колесом...'],
[20_000, 'Теперь он использует её как скейтборд...'],
[30_000, 'Брок проехал мимо отдела напитков...'],
[15_000, 'Сотрудник делает замечание...'],
[15_000, 'Брок не слышит — он в наушниках...'],
[20_000, 'Брок врезался в пирамиду из консервов...'],
[25_000, 'Консервы разлетелись'],
[15_000, 'Брок помогает собирать, напевая оперу...'],
[10_000, 'Импровизированный концерт у полки с томатами.'],
[10_000, 'Перезагрузите страницу?'],
],
[
[10_000, 'Брок идёт к выходу, его останавливает охранник...'],
[10_000, 'Охранник просит показать чек...'],
[10_000, 'Брок показывает купон на скидку...'],
[10_000, 'Охранник терпеливо объясняет разницу...'],
[10_000, 'Брок делает вид, что не понимает по-русски...'],
[10_000, 'Охранник переходит на английский, французский...'],
[10_000, 'Брок отвечает на клингонском'],
[10_000, 'Охранник оказывается фанатом «Звёздного пути»'],
[10_000, 'Они уже пьют кофе и обсуждают спин-оффы.']
],
[
[10_000, 'Брок свернул не туда и оказался в отделе игрушек...'],
[10_000, 'Брок застыл перед полкой с резиновыми уточками...'],
[10_000, 'Брок нажимает на всех уточек по очереди...'],
[10_000, 'Магазин наполняется хором пищащих уток...'],
[10_000, 'Сотрудник пытается остановить, но Брок уже дирижирует...'],
[10_000, 'Покупатели подхватывают, достают уточек из корзин...'],
[10_000, 'Флешмоб пищащих уток выходит из-под контроля...'],
[10_000, 'Брок покидает отдел под овации, оставив уточку в кармане.'],
[10_000, 'Брока вернёт лишь перезагрузка страницы'],
]
] as const;
export function useCartPolling({
enabled,
onProductsChange,
@ -25,6 +122,17 @@ export function useCartPolling({
let cancelled = false;
let missing_timeout: ReturnType<typeof setTimeout> | null = null;
let missing_scenario_index = Math.round(Math.random() * missing_scenarios.length);
let missing_scenario_element = -1;
const timeoutFunction = () => {
console.log(missing_scenario_index);
missing_scenario_element++;
setDisplayText(missing_scenarios[missing_scenario_index][missing_scenario_element][1])
missing_timeout = setTimeout(timeoutFunction, missing_scenarios[missing_scenario_index][missing_scenario_element][0]);
};
async function tick() {
try {
onLoadingChange(true);
@ -33,18 +141,29 @@ export function useCartPolling({
if (cancelled) return;
if (update.status === 'waiting') {
if (!missing_timeout) {
missing_timeout = setTimeout(() => {
setDisplayText('Ищем Брока...')
timeoutFunction();
}, 10_000);
}
setDisplayText('Брок бегает по супермаркету...')
timeoutRef.current = window.setTimeout(tick, 2000);
return;
} else if (missing_timeout) {
clearTimeout(missing_timeout);
}
if (update.status === 'complete') {
onLoadingChange(false);
onComplete();
return;
}
if (update.status === 'waiting') {
setDisplayText('Брок бегает по супермаркету...')
return;
}
if (update.status === 'clear') {
const nextProducts = update.payload?.chunk?.map(product => normalizeProductImage(product)) ?? [];
timeoutRef.current = window.setTimeout(tick, 3000);
onProductsChange(nextProducts);
}
@ -72,9 +191,9 @@ export function useCartPolling({
setDisplayText('Брок закинул пару товаров...')
}
timeoutRef.current = window.setTimeout(tick, 3000);
timeoutRef.current = window.setTimeout(tick, 5000);
} catch (error) {
setDisplayText('Ищем Брока...')
setDisplayText('Нет связи с супермаркетом...')
timeoutRef.current = window.setTimeout(tick, 3000);
}
}

View File

@ -1892,7 +1892,7 @@ let showMoreBtn;
let remainingSpan;
let initialData_g;
const cartPolicy = trustedTypes.createPolicy('cartPolicy', {
const cartPolicy = window.trustedTypes.createPolicy('cartPolicy', {
createHTML: (string) => string
});