@mimo-live-sales/faststore-sdk
v1.0.0
Published
Mimo Live Commerce SDK para VTEX FastStore - Integração de Player de Lives e PIP
Readme
@mimo/faststore-sdk
SDK oficial da Mimo para integração com VTEX FastStore. Permite adicionar funcionalidades de Live Commerce em lojas FastStore com integração nativa ao carrinho.
Funcionalidades
- MimoPlayer: Player de Lives com add-to-cart integrado
- MimoPip: Widget Picture-in-Picture flutuante
- Integração automática com
@faststore/sdkpara manipulação de carrinho - TypeScript first com tipos completos
- Compatível com React 18+ e Next.js 13+
Instalação
npm install @mimo/faststore-sdk
# ou
yarn add @mimo/faststore-sdk
# ou
pnpm add @mimo/faststore-sdkPeer Dependencies
Este pacote requer as seguintes dependências instaladas no seu projeto:
{
"@faststore/sdk": ">=2.0.0",
"react": ">=18.0.0",
"react-dom": ">=18.0.0"
}Guia de Início Rápido
Passo 1: Instale o pacote
npm install @mimo/faststore-sdkPasso 2: Identifique seu hook useCart
Projetos FastStore geralmente têm um hook useCart em src/sdk/cart. Localize-o:
# Procure no seu projeto:
find src -name "cart*" -type fPasso 3: Adicione o Player em uma página
// src/pages/live.tsx
import { MimoPlayer } from '@mimo/faststore-sdk';
import { useCart } from 'src/sdk/cart'; // ← Seu hook de carrinho
export default function LivePage() {
const { addItem, id: cartId } = useCart();
return (
<MimoPlayer
liveId="COLE_SEU_LIVE_ID_AQUI"
addToCart={addItem}
cartId={cartId}
/>
);
}Passo 4: (Opcional) Adicione o PIP global
// No seu layout principal
import { MimoPip } from '@mimo/faststore-sdk';
import { useCart } from 'src/sdk/cart';
function Layout({ children }) {
const { addItem } = useCart();
return (
<>
{children}
<MimoPip
customerId="SEU_CUSTOMER_ID"
addToCart={addItem}
/>
</>
);
}Pronto! Sua loja já está com Live Commerce integrado.
Uso
MimoPlayer - Player de Lives
O componente MimoPlayer renderiza o player de lives da Mimo com integração ao carrinho FastStore.
Importante: Você precisa fornecer a função addToCart do seu projeto FastStore.
import { MimoPlayer } from '@mimo/faststore-sdk';
import { useCart } from 'src/sdk/cart'; // Hook do seu projeto FastStore
function LivePage() {
const { addItem, id: cartId } = useCart();
return (
<MimoPlayer
liveId="sua-live-id"
addToCart={addItem}
cartId={cartId}
height="600px"
addToCartSuccessMessage="Produto adicionado!"
onAddToCart={(item) => {
console.log('Produto adicionado:', item);
}}
/>
);
}Props do MimoPlayer
| Prop | Tipo | Obrigatório | Default | Descrição |
|---------------------------|----------------------------|-------------|--------------------|-----------|
| liveId | string | ✅ | - | ID da live no sistema Mimo |
| addToCart | (item: CartItem) => void | ✅ | - | Função para adicionar ao carrinho (do useCart) |
| cartId | string | - | - | ID do carrinho atual (melhora integração) |
| height | string | - | "800px" | Altura do player |
| width | string | - | "100%" | Largura do player |
| defaultSeller | string | - | "1" | Seller ID para add to cart |
| addToCartSuccessMessage | string | - | "Produto adicionado ao carrinho!" | Mensagem de sucesso |
| onAddToCart | (item: CartItem) => void | - | - | Callback após adicionar ao carrinho |
| onError | (error: Error) => void | - | - | Callback em caso de erro |
| className | string | - | "" | Classes CSS adicionais |
| loadingText | string | - | "Carregando player..." | Texto durante carregamento |
| noLiveText | string | - | "Nenhuma live disponível..." | Texto quando sem live |
MimoPip - Picture-in-Picture
O componente MimoPip adiciona o widget flutuante PIP. Deve ser adicionado uma única vez no layout principal.
// No layout principal (layout.tsx ou _app.tsx)
import { MimoPip } from '@mimo/faststore-sdk';
import { useCart } from 'src/sdk/cart';
export default function RootLayout({ children }) {
const { addItem } = useCart();
return (
<html>
<body>
{children}
<MimoPip
customerId="seu-customer-id"
addToCart={addItem}
/>
</body>
</html>
);
}Props do MimoPip
| Prop | Tipo | Obrigatório | Default | Descrição |
|-----------------|----------------------------|-------------|---------|-----------|
| customerId | string | ✅ | - | Customer ID da conta Mimo |
| addToCart | (item: CartItem) => void | ✅ | - | Função para adicionar ao carrinho |
| defaultSeller | string | - | "1" | Seller ID para add to cart |
| onAddToCart | (item: CartItem) => void | - | - | Callback após adicionar ao carrinho |
| onError | (error: Error) => void | - | - | Callback em caso de erro |
Exemplos Práticos
Exemplo 1: Página de Live Dedicada
Crie uma página dedicada para transmissões ao vivo:
// src/pages/live/[liveId].tsx
import { useRouter } from 'next/router';
import { MimoPlayer } from '@mimo/faststore-sdk';
import { useCart } from 'src/sdk/cart';
export default function LivePage() {
const router = useRouter();
const { liveId } = router.query;
const { addItem, id: cartId } = useCart();
// Aguarda o liveId estar disponível (hydration)
if (!liveId || typeof liveId !== 'string') {
return (
<div className="flex items-center justify-center min-h-screen">
<p>Carregando...</p>
</div>
);
}
return (
<main className="min-h-screen bg-gray-50">
{/* Header da página */}
<header className="bg-white shadow-sm py-4">
<div className="container mx-auto px-4">
<h1 className="text-2xl font-bold text-gray-900">
Live Shopping
</h1>
<p className="text-gray-600">
Assista e compre produtos em tempo real!
</p>
</div>
</header>
{/* Player */}
<section className="container mx-auto px-4 py-8">
<MimoPlayer
liveId={liveId}
addToCart={addItem}
cartId={cartId}
height="600px"
className="rounded-lg overflow-hidden shadow-lg"
addToCartSuccessMessage="Produto adicionado ao carrinho!"
loadingText="Preparando a transmissão..."
noLiveText="Esta live não está disponível no momento."
onAddToCart={(item) => {
// Analytics ou tracking personalizado
console.log('Produto adicionado via Live:', item);
}}
onError={(error) => {
console.error('Erro no player:', error);
}}
/>
</section>
</main>
);
}Exemplo 2: Player em Modal/Popup
Exiba o player em um modal que pode ser aberto de qualquer página:
// src/components/LiveModal/LiveModal.tsx
import { useState, useEffect } from 'react';
import { MimoPlayer } from '@mimo/faststore-sdk';
import { useCart } from 'src/sdk/cart';
interface LiveModalProps {
liveId: string;
isOpen: boolean;
onClose: () => void;
}
export function LiveModal({ liveId, isOpen, onClose }: LiveModalProps) {
const { addItem, id: cartId } = useCart();
const [mounted, setMounted] = useState(false);
// Evita hydration mismatch
useEffect(() => {
setMounted(true);
}, []);
if (!mounted || !isOpen) return null;
return (
<div className="fixed inset-0 z-50 flex items-center justify-center">
{/* Overlay */}
<div
className="absolute inset-0 bg-black/70"
onClick={onClose}
/>
{/* Modal */}
<div className="relative w-full max-w-4xl mx-4 bg-white rounded-xl overflow-hidden shadow-2xl">
{/* Header */}
<div className="flex items-center justify-between p-4 border-b">
<h2 className="text-lg font-semibold">Assista nossa Live!</h2>
<button
onClick={onClose}
className="p-2 hover:bg-gray-100 rounded-full transition"
>
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
{/* Player */}
<MimoPlayer
liveId={liveId}
addToCart={addItem}
cartId={cartId}
height="500px"
/>
</div>
</div>
);
}
// Uso em qualquer página:
//
// const [showLive, setShowLive] = useState(false);
//
// <button onClick={() => setShowLive(true)}>
// Assistir Live
// </button>
//
// <LiveModal
// liveId="abc123"
// isOpen={showLive}
// onClose={() => setShowLive(false)}
// />Exemplo 3: Banner com CTA para Live
Crie um banner promocional que leva para a live:
// src/components/LiveBanner/LiveBanner.tsx
import Link from 'next/link';
interface LiveBannerProps {
liveId: string;
title: string;
description?: string;
scheduledTime?: string;
backgroundImage?: string;
}
export function LiveBanner({
liveId,
title,
description,
scheduledTime,
backgroundImage,
}: LiveBannerProps) {
return (
<section
className="relative w-full py-16 bg-gradient-to-r from-purple-600 to-pink-500"
style={backgroundImage ? {
backgroundImage: `url(${backgroundImage})`,
backgroundSize: 'cover',
backgroundPosition: 'center',
} : undefined}
>
{/* Overlay para melhorar legibilidade */}
{backgroundImage && (
<div className="absolute inset-0 bg-black/40" />
)}
<div className="relative container mx-auto px-4 text-center text-white">
{/* Badge ao vivo */}
<span className="inline-flex items-center gap-2 px-3 py-1 bg-red-500 rounded-full text-sm font-medium mb-4">
<span className="w-2 h-2 bg-white rounded-full animate-pulse" />
AO VIVO
</span>
<h2 className="text-3xl md:text-4xl font-bold mb-2">
{title}
</h2>
{description && (
<p className="text-lg text-white/90 mb-4 max-w-2xl mx-auto">
{description}
</p>
)}
{scheduledTime && (
<p className="text-white/80 mb-6">
{scheduledTime}
</p>
)}
<Link
href={`/live/${liveId}`}
className="inline-flex items-center gap-2 px-8 py-3 bg-white text-purple-600 font-semibold rounded-full hover:bg-gray-100 transition shadow-lg"
>
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path d="M6.3 2.841A1.5 1.5 0 004 4.11V15.89a1.5 1.5 0 002.3 1.269l9.344-5.89a1.5 1.5 0 000-2.538L6.3 2.84z" />
</svg>
Assistir Agora
</Link>
</div>
</section>
);
}Exemplo 4: Layout Global com PIP
Configure o PIP para funcionar em todas as páginas:
// src/components/Layout/Layout.tsx
import { ReactNode } from 'react';
import { MimoPip } from '@mimo/faststore-sdk';
import { useCart } from 'src/sdk/cart';
import Header from '../Header';
import Footer from '../Footer';
interface LayoutProps {
children: ReactNode;
}
export function Layout({ children }: LayoutProps) {
const { addItem } = useCart();
// Seu Customer ID da Mimo (pode vir de env vars)
const MIMO_CUSTOMER_ID = process.env.NEXT_PUBLIC_MIMO_CUSTOMER_ID;
return (
<>
<Header />
<main className="min-h-screen">
{children}
</main>
<Footer />
{/* PIP - Widget flutuante global */}
{MIMO_CUSTOMER_ID && (
<MimoPip
customerId={MIMO_CUSTOMER_ID}
addToCart={addItem}
onAddToCart={(item) => {
// Opcional: mostrar notificação, analytics, etc.
console.log('Produto adicionado via PIP:', item);
}}
onError={(error) => {
console.error('Erro no PIP:', error);
}}
/>
)}
</>
);
}// src/pages/_app.tsx (Next.js Pages Router)
import type { AppProps } from 'next/app';
import { Layout } from 'src/components/Layout';
import { CartProvider } from 'src/sdk/cart';
export default function App({ Component, pageProps }: AppProps) {
return (
<CartProvider>
<Layout>
<Component {...pageProps} />
</Layout>
</CartProvider>
);
}Exemplo 5: Integração com Analytics
Rastreie eventos de add to cart da live para analytics:
// src/components/MimoPlayerWithAnalytics.tsx
import { MimoPlayer, CartItem } from '@mimo/faststore-sdk';
import { useCart } from 'src/sdk/cart';
import { sendAnalyticsEvent } from '@faststore/sdk';
interface MimoPlayerWithAnalyticsProps {
liveId: string;
liveName?: string;
}
export function MimoPlayerWithAnalytics({
liveId,
liveName = 'Live Shopping'
}: MimoPlayerWithAnalyticsProps) {
const { addItem, id: cartId } = useCart();
const handleAddToCart = (item: CartItem) => {
// Envia evento para Google Analytics / FastStore Analytics
sendAnalyticsEvent({
name: 'add_to_cart',
params: {
currency: 'BRL',
value: 0, // O SDK Mimo não fornece preço
items: [{
item_id: item.id,
item_name: `SKU ${item.id}`,
quantity: item.quantity,
// Dados extras para identificar origem
item_list_name: liveName,
item_list_id: liveId,
}],
},
});
// Custom event para identificar que veio da Live
sendAnalyticsEvent({
name: 'mimo_live_add_to_cart',
params: {
live_id: liveId,
live_name: liveName,
sku_id: item.id,
quantity: item.quantity,
},
});
};
return (
<MimoPlayer
liveId={liveId}
addToCart={addItem}
cartId={cartId}
height="600px"
onAddToCart={handleAddToCart}
/>
);
}Exemplo 6: Player com Toast Notification Customizado
Use seu próprio sistema de notificações:
// src/components/MimoPlayerWithToast.tsx
import { MimoPlayer, CartItem } from '@mimo/faststore-sdk';
import { useCart } from 'src/sdk/cart';
import { useUI } from 'src/sdk/ui'; // Hook de UI do seu projeto
// ou use: import { toast } from 'react-hot-toast';
export function MimoPlayerWithToast({ liveId }: { liveId: string }) {
const { addItem, id: cartId } = useCart();
const { openMinicart, pushToast } = useUI();
const handleAddToCart = (item: CartItem) => {
// Mostra toast personalizado
pushToast({
title: 'Adicionado ao carrinho!',
message: `SKU ${item.id} (${item.quantity}x)`,
status: 'success',
icon: '🛒',
});
// Abre o minicart automaticamente
openMinicart();
};
const handleError = (error: Error) => {
pushToast({
title: 'Erro ao adicionar',
message: error.message,
status: 'error',
});
};
return (
<MimoPlayer
liveId={liveId}
addToCart={addItem}
cartId={cartId}
onAddToCart={handleAddToCart}
onError={handleError}
// Desabilita mensagem padrão do SDK Mimo
addToCartSuccessMessage=""
/>
);
}Exemplo 7: Múltiplos Sellers (Marketplace)
Configure diferentes sellers para diferentes lives:
// src/pages/live/[liveId].tsx
import { MimoPlayer } from '@mimo/faststore-sdk';
import { useCart } from 'src/sdk/cart';
// Mapeamento de lives para sellers
const LIVE_SELLER_MAP: Record<string, string> = {
'live-loja-oficial': '1',
'live-parceiro-abc': '2',
'live-seller-xyz': '3',
};
export default function LivePage({ liveId }: { liveId: string }) {
const { addItem, id: cartId } = useCart();
// Determina o seller baseado na live
const sellerId = LIVE_SELLER_MAP[liveId] || '1';
return (
<MimoPlayer
liveId={liveId}
addToCart={addItem}
cartId={cartId}
defaultSeller={sellerId}
height="600px"
/>
);
}
export async function getServerSideProps({ params }) {
return {
props: {
liveId: params.liveId,
},
};
}Exemplo 8: Configuração via Variáveis de Ambiente
Centralize configurações usando env vars:
# .env.local
NEXT_PUBLIC_MIMO_CUSTOMER_ID=seu-customer-id-aqui
NEXT_PUBLIC_MIMO_DEFAULT_SELLER=1
NEXT_PUBLIC_MIMO_PLAYER_HEIGHT=700px// src/config/mimo.ts
export const MIMO_CONFIG = {
customerId: process.env.NEXT_PUBLIC_MIMO_CUSTOMER_ID || '',
defaultSeller: process.env.NEXT_PUBLIC_MIMO_DEFAULT_SELLER || '1',
playerHeight: process.env.NEXT_PUBLIC_MIMO_PLAYER_HEIGHT || '800px',
} as const;// src/components/MimoLive.tsx
import { MimoPlayer, MimoPip } from '@mimo/faststore-sdk';
import { useCart } from 'src/sdk/cart';
import { MIMO_CONFIG } from 'src/config/mimo';
export function MimoLive({ liveId }: { liveId: string }) {
const { addItem, id: cartId } = useCart();
return (
<MimoPlayer
liveId={liveId}
addToCart={addItem}
cartId={cartId}
defaultSeller={MIMO_CONFIG.defaultSeller}
height={MIMO_CONFIG.playerHeight}
/>
);
}
export function MimoPipGlobal() {
const { addItem } = useCart();
if (!MIMO_CONFIG.customerId) return null;
return (
<MimoPip
customerId={MIMO_CONFIG.customerId}
addToCart={addItem}
defaultSeller={MIMO_CONFIG.defaultSeller}
/>
);
}Integração com Headless CMS
Criando uma Section para o MimoPlayer
// src/components/sections/MimoLiveSection/MimoLiveSection.tsx
import { MimoPlayer } from '@mimo/faststore-sdk';
import { useCart } from 'src/sdk/cart';
interface MimoLiveSectionProps {
liveId: string;
height?: string;
successMessage?: string;
}
export function MimoLiveSection({
liveId,
height = '800px',
successMessage = 'Produto adicionado!',
}: MimoLiveSectionProps) {
const { addItem, id: cartId } = useCart();
return (
<section className="w-full py-8">
<div className="container mx-auto px-4">
<MimoPlayer
liveId={liveId}
addToCart={addItem}
cartId={cartId}
height={height}
addToCartSuccessMessage={successMessage}
/>
</div>
</section>
);
}Schema para o CMS
{
"MimoLiveSection": {
"title": "Mimo Live Player",
"description": "Seção com player de Live Commerce da Mimo",
"type": "object",
"required": ["liveId"],
"properties": {
"liveId": {
"title": "ID da Live",
"type": "string",
"description": "ID da transmissão no painel Mimo"
},
"height": {
"title": "Altura do Player",
"type": "string",
"default": "800px",
"description": "Altura em pixels ou porcentagem"
},
"successMessage": {
"title": "Mensagem de Sucesso",
"type": "string",
"default": "Produto adicionado ao carrinho!",
"description": "Mensagem exibida ao adicionar produto"
}
}
}
}Hooks Disponíveis
useMimoCart
Hook para integração manual com o carrinho. Útil se você precisar customizar a lógica:
import { useMimoCart } from '@mimo/faststore-sdk';
import { useCart } from 'src/sdk/cart';
function MyComponent() {
const { addItem: faststoreAddItem } = useCart();
const { addItemFromMimo, addItem } = useMimoCart({
addToCart: faststoreAddItem,
defaultSeller: '1',
onSuccess: (item) => console.log('Adicionado:', item),
onError: (error) => console.error('Erro:', error),
});
// Adicionar item diretamente
const handleAddItem = () => {
addItem({
id: 'sku-123',
quantity: 1,
seller: '1',
});
};
return <button onClick={handleAddItem}>Adicionar</button>;
}useScript
Hook para carregar scripts externos:
import { useScript } from '@mimo/faststore-sdk';
function MyComponent() {
const { isReady, isLoading, isError } = useScript(
'https://example.com/script.js',
{
id: 'my-script',
onLoad: () => console.log('Carregado!'),
}
);
if (isLoading) return <p>Carregando...</p>;
if (isError) return <p>Erro ao carregar</p>;
return <div>Script pronto!</div>;
}TypeScript
O pacote inclui tipos completos. Principais tipos exportados:
import type {
MimoPlayerProps,
MimoPipProps,
CartItem,
MimoProductVariant,
MimoAddToCartPayload,
} from '@mimo/faststore-sdk';Migração do VTEX IO
Se você está migrando do app VTEX IO mimobr.mimo-livecommerce, aqui está o mapeamento:
| VTEX IO | FastStore SDK |
|---------|---------------|
| Block mimoplayer | Componente <MimoPlayer /> |
| Pixel head.html (PIP) | Componente <MimoPip /> |
| useOrderItems() | Integrado via @faststore/sdk |
| Configuração via Admin | Configuração via props/CMS |
Antes (VTEX IO)
// store/blocks.jsonc
{
"store.custom#live": {
"children": ["mimoplayer"]
}
}Depois (FastStore)
// pages/live.tsx
import { MimoPlayer } from '@mimo/faststore-sdk';
import { useCart } from 'src/sdk/cart';
export default function LivePage() {
const { addItem, id: cartId } = useCart();
return (
<MimoPlayer
liveId="abc123"
addToCart={addItem}
cartId={cartId}
/>
);
}FAQ / Troubleshooting
Onde encontro o liveId?
O liveId é o identificador único da sua transmissão. Você pode encontrá-lo no painel administrativo da Mimo após criar uma live. Geralmente é uma string como "abc123def456".
Onde encontro o customerId?
O customerId é o identificador da sua conta Mimo. Entre em contato com o suporte da Mimo ([email protected]) para obter seu ID.
O player não aparece / fica em branco
- Verifique o
liveId: Certifique-se de que o ID da live está correto e a live existe - Verifique o console: Abra o DevTools (F12) e veja se há erros no console
- Verifique a rede: Na aba Network, veja se o script
sdk.mimo.com.brestá carregando
Erro "addToCart is not a function"
Você precisa passar a função addToCart do seu hook de carrinho:
// ❌ Errado
<MimoPlayer liveId="abc" />
// ✅ Correto
const { addItem } = useCart();
<MimoPlayer liveId="abc" addToCart={addItem} />Produtos não estão sendo adicionados ao carrinho
- Verifique o
seller: O seller padrão é"1". Se sua loja usa outro seller, configure viadefaultSeller - Verifique o SKU: O SKU do produto na Mimo deve corresponder ao SKU no catálogo VTEX
- Verifique o callback
onError: Adicione para ver erros:
<MimoPlayer
liveId="abc"
addToCart={addItem}
onError={(error) => console.error('Erro:', error)}
/>Como testar localmente?
- Use uma live de teste fornecida pela Mimo
- Ou crie uma live no ambiente de staging da Mimo
- Configure variáveis de ambiente para facilitar:
# .env.local
NEXT_PUBLIC_MIMO_LIVE_ID=sua-live-de-testeO PIP não aparece
- O PIP só aparece se houver conteúdo ativo na conta
- Verifique se o
customerIdestá correto - O componente
MimoPipdeve estar no layout global (renderizado em todas as páginas)
Posso customizar o estilo do player?
O player da Mimo é renderizado dentro de um iframe, então estilos CSS não afetam seu conteúdo interno. Você pode:
- Usar
classNamepara estilizar o container externo - Usar
heightewidthpara dimensões - Customizações internas devem ser feitas no painel da Mimo
Como funciona em SSR (Server-Side Rendering)?
Os componentes usam 'use client' e só carregam os scripts no browser. O SSR renderiza um placeholder/loading state que é hidratado no cliente.
Suporte a React Native / Mobile Apps
Este SDK é apenas para web (React/Next.js). Para apps mobile, entre em contato com a Mimo para soluções específicas.
Suporte
- Email: [email protected]
- Site: https://mimo.com.br
- Formulário: https://mimo.com.br/form
- Documentação VTEX: https://developers.vtex.com/docs/guides/faststore
Licença
MIT © Mimo
