Files
shop-server/docs/superpowers/specs/2026-05-25-cart-added-snackbar-design.md
T
2026-05-25 17:04:57 +05:00

3.2 KiB
Raw Blame History

Cart Added Snackbar — Design Spec

Date: 2026-05-25

Goal

При добавлении товара в корзину показывать глобальное уведомление (Snackbar) с кнопкой «Перейти в корзину».

Scope

  • AddToCartButton (каталог, карточки товаров)
  • ToggleCartIcon (страница товара, toggle add/remove)
  • Глобальный Snackbar, рендерится один раз

Architecture

1. Effector store — shared/model/cart-notifications.ts

Минимальный стор: только булев флаг открытия.

import { createEvent, createStore } from 'effector'

export const cartAdded = createEvent()
export const cartDismissed = createEvent()

export const $cartSnackOpen = createStore(false)
  .on(cartAdded, () => true)
  .on(cartDismissed, () => false)

2. UI Component — shared/ui/CartSnackbar.tsx

Компонент подписывается на $cartSnackOpen через useUnit.

  • Текст: «Товар добавлен в корзину»
  • Кнопка действия: «Перейти в корзину» → navigate('/cart') + cartDismissed()
  • Закрытие (крестик): cartDismissed()
  • Авто-закрытие: 4 секунды через setTimeout
  • Позиция: anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
  • Стиль: MUI <Snackbar> + <Alert severity="success">

Если пользователь быстро добавит несколько товаров — каждый cartAdded() перезапускает таймер. Очередь не нужна.

3. Интеграция в AddToCartButton

В onSuccess мутации добавляется cartAdded():

const addMut = useMutation({
  mutationFn: () => addToCart({ productId, qty }),
  onSuccess: () => {
    void qc.invalidateQueries({ queryKey: ['me', 'cart'] })
    cartAdded()
  },
})

productTitle не передаётся — текст уведомления универсальный.

4. Интеграция в ToggleCartIcon

Только add-мутация:

const addMut = useMutation({
  mutationFn: () => addToCart({ productId, qty: 1 }),
  onSuccess: () => {
    void qc.invalidateQueries({ queryKey: ['me', 'cart'] })
    cartAdded()
  },
})

Remove-мутация без уведомления.

5. Mount point — app/AppProviders.tsx

<CartSnackbar /> рендерится один раз в AppProviders.tsx (или App.tsx), чтобы быть доступным во всём приложении.

Dependencies

  • effector / effector-react (уже используется)
  • @mui/material — Snackbar, Alert (уже используется)
  • react-router-dom — useNavigate (уже используется)

Testing

  • Unit-тест CartSnackbar: открывается по cartAdded(), закрывается по cartDismissed()
  • Unit-тест AddToCartButton: вызывает cartAdded() в onSuccess
  • Unit-тест ToggleCartIcon: вызывает cartAdded() только для add-мутации