SubSovereign
All guides

SubSovereign w React (web) — przewodnik integracji

Ten przewodnik dotyczy @subsovereign/react (sdk-react/) — warstwy UI paywall dla aplikacji internetowych React. Renderuje paywall zaprojektowany w panelu SubSovereign jako rzeczywiste komponenty React, przy użyciu tego samego silnika renderującego, którego używa podgląd panelu, dzięki czemu to, co zatwierdzasz w panelu, trafia do aplikacji bez zmian.

Ten SDK rysuje paywall; nie zajmuje się rozliczeniami ani uprawnieniami. Użyj go razem z Web/JS data SDK (@subsovereign/js-sdk) do checkEntitlements() oraz walidacji zakupu — oba SDK są zaprojektowane do współpracy.

Zanim zaczniesz

Będziesz potrzebować działającego serwera SubSovereign, zarejestrowanej aplikacji w panelu (z appId i kluczem API w roli SDK), oraz opublikowanego paywalla (panel → Paywall → Publikuj).

Krok 1 — Instalacja

Pakiet znajduje się w sdk-react/ i nie jest jeszcze dostępny na npm — dodaj go jako zależność lokalną lub z git (lub skopiuj folder do swojego projektu):

npm install ./sdk-react   # path dependency while it's pre-npm
import { Paywall, usePaywallConfig } from '@subsovereign/react';

Krok 2 — Załaduj opublikowany paywall

usePaywallConfig pobiera konfigurację dla tej aplikacji/użytkownika. Wariant A/B jest wybierany po stronie serwera na podstawie userId, dzięki czemu ten sam użytkownik zawsze widzi ten sam paywall.

const { config, loading, error } = usePaywallConfig({
  apiUrl: 'https://subs.yourdomain.com/api/v1', // YOUR self-hosted server
  appId:  'your-app-id',
  userId: currentUser.id,                        // your own stable user id
  apiKey: 'YOUR_SDK_KEY',
  locale: 'en',                                  // optional, default 'en'
  platform: 'web',                               // optional, default 'web'
});

Przekaż null zamiast parametrów, aby pominąć pobieranie (np. gdy użytkownik nie jest zalogowany).

Krok 3 — Renderuj go

<Paywall
  config={config}
  loading={loading}
  loadingState={<Spinner />}          // optional
  emptyState={<FallbackPaywall />}    // optional — shown when no config is published
  onSelectProduct={(productId) => startCheckout(productId)}
/>

onSelectProduct uruchamia się, gdy użytkownik wybierze produkt — podłącz do swojego koszyka (Stripe na stronie). Po udanym zakupie zweryfikuj zakup przy użyciu data SDK i ponownie sprawdź uprawnienia:

await SubSovereign.validateStripeSubscription({ subscriptionId, productId, accessLevelId: 'pro' });
const { hasAccess } = await SubSovereign.checkEntitlements();
if (hasAccess) unlockProFeatures();

Jeśli masz już konfigurację (pobraną przez data SDK), pomiń hook i przekaż ją bezpośrednio. Aby mieć pełną kontrolę, użyj surowego renderera: <PaywallRenderer config={config} onSelectProduct={…} />.

Przycisk odstąpienia od umowy (Compliance Passport)

Jeśli sprzedajesz subskrypcje konsumentom z UE przez internet, Dyrektywa (UE) 2023/2673 wymaga wyraźnie oznaczonej funkcji odstąpienia od umowy. SDK dostarcza ją gotową:

import { WithdrawalButton, useWithdrawalConfig } from '@subsovereign/react';

function CancelSubscription({ user, sub }: { user: { id: string; locale: string }; sub: { id: string } }) {
  // Fetches the withdrawal settings AND the notice's wording in the customer's language.
  const { config, strings, error } = useWithdrawalConfig({
    apiUrl: 'https://subs.yourdomain.com/api/v1',
    appId: 'your-app-id',
    apiKey: 'YOUR_SDK_KEY',
    locale: user.locale,          // the CUSTOMER's language, not your console's
  });
  // Log it: a silent failure here is how a tenant ships English to German customers and never finds
  // out. The customer is never shown this — they get the button, in English.
  if (error) console.warn('SubSovereign: withdrawal settings unavailable', error);
  if (config && config.enabled === false) return null;   // the tenant turned it off

  return (
    <WithdrawalButton
      apiUrl="https://subs.yourdomain.com/api/v1"
      appId="your-app-id"
      apiKey="YOUR_SDK_KEY"
      userId={user.id}
      subscriptionId={sub.id}
      strings={strings}           // ← without this the dialog is ENGLISH for every customer
      locale={user.locale}        // ← and without this the DATE is formatted for the device
      labelKey={config?.labelKey} // ← the label the tenant chose in the console
      appearance="auto"
    />
  );
}

Nie możesz zmienić tekstu. Konsola oferuje dwa etykiety dla funkcji odstąpienia — „Odstąp od umowy tutaj” i „Anuluj tutaj” — a labelKey przenosi tę, którą wybrał właściciel aplikacji; same słowa pochodzą z serwera w języku klienta. Nie ma możliwości przekazania własnego tekstu. Właściwość label kiedyś akceptowała dowolny tekst i jest teraz ignorowana z ostrzeżeniem w konsoli: statutowe powiadomienie, które można dowolnie modyfikować, może zostać złagodzone do marketingu — to ten sam powód, dla którego nie możesz przekazać koloru.

🚩 Przekaż także locale. Formatuje znacznik czasu na potwierdzeniu. Bez niego data jest formatowana dla urządzenia, więc niemiecki klient na amerykańskiej przeglądarce zobaczy 9/3/2026 — co odczyta jako 9 marca, a nie 3 września. To data wpisu w akcie prawnym, a niejednoznaczność działa w obie strony.

🚩 Przekaż strings, bo statutowe powiadomienie będzie po angielsku dla wszystkich. Słowa są dostarczane przez twój serwer SubSovereign w żądanym języku — celowo są nasze, a nie twoje, aby statutowe powiadomienie nie zostało złagodzone do marketingu — a przycisk renderuje to, co otrzyma. Samodzielnie nie pobiera tekstów, ponieważ ten sam kontrakt komponentu musi działać na Roku, gdzie komponent UI nie może wykonywać żadnych operacji sieciowych. useWithdrawalConfig to jedyna linia łącząca oba elementy.

Jeśli pobieranie się nie powiedzie, przycisk nadal się pojawi, po angielsku, zamiast nie pojawiać się wcale. Twoim obowiązkiem jest zapewnienie widocznej funkcji odstąpienia dla konsumenta; pokazanie jej w niewłaściwym języku nie jest. Hook zwraca error, abyś mógł to zarejestrować; nigdy nie pokażesz go klientowi.

Wygląd — light, dark lub auto (domyślnie), i nic więcej. Dialog samodzielnie rysuje swoją kartę i tekst, dzięki czemu jest czytelny na każdej stronie, niezależnie od motywu; auto stosuje się do ustawień przeglądarki odwiedzającego, a w przypadku braku wykrytej preferencji domyślnie ustawia się na ciemny. Celowo nie ma możliwości przekazania koloru: to statutowe powiadomienie, którego brzmienie i kolory są ustalone, aby było czytelne dla każdego klienta każdej aplikacji. Jeśli stosujesz tę zasadę gdzie indziej w swoim UI, eksportowana jest funkcja resolveAppearance(appearance, scheme) (scheme to 'light' | 'dark' | null).

Wyświetla widoczny przycisk z etykietą, potwierdza jednokrotnie, wysyła idempotentnie (ponowna próba sieciowa nigdy nie utworzy dwóch odstąpień), i pokazuje potwierdzenie. Sam przycisk nie wykonuje żadnych operacji sieciowych poza wysłaniem, więc to od ciebie zależy, aby ograniczyć go na podstawie config.enabled i config.jurisdictions, jak powyżej. Dla potrzeb niestandardowych interfejsów użytkownika eksportowane są funkcje niższego poziomu (fetchWithdrawalConfig, useWithdrawal, submitWithdrawal).

Szybki przegląd

Chcesz… Użyj
Załadować opublikowany paywall usePaywallConfig(params){ config, loading, error }
Narysować go <Paywall config onSelectProduct … />
Pełna kontrola nad renderowaniem <PaywallRenderer config onSelectProduct />
Odstąpienie od umowy w UE, w języku klienta useWithdrawalConfig({…, locale}) → przekaż strings, locale i labelKey do <WithdrawalButton>
Uprawnienia / walidacja Web & React Native guide

Następne kroki