diff --git a/src/api/promoApi.ts b/src/api/promoApi.ts index 9a1a419..293e405 100644 --- a/src/api/promoApi.ts +++ b/src/api/promoApi.ts @@ -28,18 +28,19 @@ export async function loadInitialData(): Promise { 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, -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/components/Accordion/Accordion.tsx b/src/components/Accordion/Accordion.tsx index 61920dc..6098c42 100644 --- a/src/components/Accordion/Accordion.tsx +++ b/src/components/Accordion/Accordion.tsx @@ -15,17 +15,18 @@ interface AccordionProps { } export function Accordion({ - title, - description, - icon, - isOpen, - isHighlighted = true, - onToggle, - children, - }: AccordionProps) { + id, + title, + description, + icon, + isOpen, + isHighlighted = true, + onToggle, + children, +}: AccordionProps) { return ( -
+
{icon ?? } @@ -58,7 +59,7 @@ const Item = styled.div` } `; -const Header = styled.button` +const Header = styled.div` width: 100%; display: flex; align-items: center; diff --git a/src/hooks/useCartPolling.ts b/src/hooks/useCartPolling.ts index 7082c81..c89a228 100644 --- a/src/hooks/useCartPolling.ts +++ b/src/hooks/useCartPolling.ts @@ -11,6 +11,103 @@ interface UseCartPollingParams { setDisplayText: Dispatch>; } +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 | 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); } } diff --git a/src_static/autocart.js b/src_static/autocart.js index 76a0816..7cf6c26 100644 --- a/src_static/autocart.js +++ b/src_static/autocart.js @@ -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 });