AO VIVO · AUDIT CHAIN · UE
SISTEMA · 99,99% DISPONIBILIDADE
v 1.0 ↗ FEITO NA UE

@nexbasira/react

Wrapper React em torno de @nexbasira/embed. Duas superfícies — um componente <NexBasiraSession> pronto a usar para o caso comum, mais um hook useNexBasiraSession() para layouts personalizados.

Instalação

npm install @nexbasira/react @nexbasira/embed react

react e @nexbasira/embed são peer dependencies — não vêm agrupados neste pacote.

Componente

import { NexBasiraSession } from "@nexbasira/react";

function InspectionPage({ joinUrl }: { joinUrl: string }) {
  return (
    <NexBasiraSession
      sessionUrl={joinUrl}
      height="720px"
      onSessionComplete={(id) => navigate(`/inspections/${id}`)}
    />
  );
}

sessionUrl é o URL de uso único que o seu backend recebe de sessions.invite() no SDK Node / Python. O componente monta o iframe no primeiro render e destrói-o de forma limpa ao desmontar.

Acesso imperativo via ref

Use um ref quando os controlos do lado do terreno vivem fora do iframe (toolbar acima do componente, gatilho de modal, etc.):

import { useRef } from "react";
import { NexBasiraSession, type NexBasiraSessionHandle } from "@nexbasira/react";

function Toolbar({ joinUrl }: { joinUrl: string }) {
  const session = useRef<NexBasiraSessionHandle>(null);
  return (
    <>
      <button onClick={() => session.current?.requestSnapshot()}>Capture</button>
      <button onClick={() => session.current?.openWhiteboard()}>Whiteboard</button>
      <button onClick={() => session.current?.endSession()}>End</button>
      <NexBasiraSession ref={session} sessionUrl={joinUrl} />
    </>
  );
}

Variante com hook

Quando o <div> do wrapper não se adequa ao seu layout — digamos que quer o iframe num contentor flex com uma sidebar — use o hook + anexe o ref devolvido ao seu próprio elemento anfitrião:

import { useNexBasiraSession } from "@nexbasira/react";

function CustomLayout({ joinUrl }: { joinUrl: string }) {
  const [containerRef, widget] = useNexBasiraSession({
    sessionUrl: joinUrl,
    onSessionComplete: (id) => navigate(`/inspections/${id}`),
  });

  return (
    <div className="grid grid-cols-[1fr_240px] gap-4">
      <div ref={containerRef} style={{ minHeight: 600 }} />
      <aside>
        <button onClick={() => widget.current?.requestSnapshot()}>Snap</button>
      </aside>
    </div>
  );
}

Os callbacks de ciclo de vida mantêm-se atualizados entre renders

O widget de embed é criado uma vez por sessionUrl. Para garantir que os seus callbacks veem sempre a closure mais recente (fechando sobre o estado mais recente), o wrapper guarda-os internamente num useRef e relê-os a cada evento. Pode passar funções arrow inline com segurança:

function Page() {
  const [count, setCount] = useState(0);
  return (
    <NexBasiraSession
      sessionUrl={joinUrl}
      onEvidenceAdded={() => {
        // 'count' is always the latest value, not the value at mount
        setCount(count + 1);
      }}
    />
  );
}

Quando é que o iframe é reconstruído?

Apenas quando sessionUrl muda. Qualquer outra prop (callbacks, width, height, expectedOrigin) aplica-se no local sem remontar. Isto significa que mudar um callback ou redimensionar o anfitrião não reinicia a sessão em direto — útil quando a sua aplicação faz re-render com frequência.

Props

PropTipoNotas
sessionUrlstringObrigatório. Emitido pelo seu backend.
width / heightstringTamanhos CSS. Por defeito 100% / 600px.
expectedOriginstringSobrepõe a origem do iframe se alojar num domínio personalizado.
classNamestringAplicado ao div do wrapper.
styleCSSPropertiesAplicado ao div do wrapper.
on* callbacksfunctionMesma superfície que @nexbasira/embed — ver essa página.

Handle tipado

import type { NexBasiraSessionHandle } from "@nexbasira/react";

const ref = useRef<NexBasiraSessionHandle>(null);
// ref.current has typed methods: requestSnapshot(), openWhiteboard(), etc.

O que vem a seguir