@snapkyc-ooru/consent-handoff-react 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,158 @@
1
+ # @snapkyc/consent-handoff-react
2
+
3
+ React + TypeScript SDK for the **integrations agreement → transaction initiate → QR _or_ intent → status polling** flow. `API_ORIGIN` is fixed in [`src/config.ts`](src/config.ts) (currently `http://127.0.0.1:8000`). Relying parties pass a single **`integrationToken`** (`Authorization: Token …`). See [`docs/HTTP_CONTRACT.md`](docs/HTTP_CONTRACT.md) for route assumptions.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @snapkyc/consent-handoff-react react react-dom
9
+ ```
10
+
11
+ ## Styles
12
+
13
+ ```tsx
14
+ import "@snapkyc/consent-handoff-react/styles.css";
15
+ ```
16
+
17
+ Design tokens are scoped to the SDK root (`.snap-consent-handoff`). If you previously overrode appearance by targeting **`:root`**, switch to the **`theme` prop** (see below) or to selectors under `.snap-consent-handoff` so you do not affect the host application.
18
+
19
+ ## Theme (optional)
20
+
21
+ Pass **`theme`** with any subset of fields; the rest use the built-in warm default palette (orange primary, cream accents, light canvas). Changing **`primary`** alone updates accents and the default active border color unless you set **`borderActive`** explicitly.
22
+
23
+ | Field | Role |
24
+ |-------|------|
25
+ | `primary` | Brand color — primary buttons, checkboxes, selected borders |
26
+ | `onPrimary` | Text on primary buttons |
27
+ | `canvas` | Sheet / panel background |
28
+ | `surface` | Default “card” surfaces (e.g. unselected purpose rows) |
29
+ | `surfaceMuted` | Agreement notice and selected purpose row background |
30
+ | `text` / `textMuted` | Body and secondary text |
31
+ | `border` / `borderActive` | Default and emphasized borders |
32
+ | `modalOverlay` | Scrim behind the modal |
33
+ | `danger` | Error text |
34
+ | `success` | Success verification icon and status checkmarks |
35
+ | `successStatusSurface` | Success screen status summary card background |
36
+ | `successPurposesSurface` | Success screen “Confirmed purposes” panel background |
37
+ | `successAccordionBorder` | Demographic accordion borders |
38
+ | `radius` | Corner radius string (e.g. `"12px"`) |
39
+ | `fontFamily` | UI font stack |
40
+ | `gap`, `maxWidth`, `modalZ` | Layout tokens |
41
+
42
+ ```tsx
43
+ import {
44
+ SnapConsentHandoffFlow,
45
+ DEFAULT_SNAP_CONSENT_THEME,
46
+ type SnapConsentHandoffTheme,
47
+ } from "@snapkyc/consent-handoff-react";
48
+
49
+ const brand: Partial<SnapConsentHandoffTheme> = {
50
+ primary: "#0f766e",
51
+ borderActive: "#0f766e",
52
+ surfaceMuted: "#f0fdfa",
53
+ };
54
+
55
+ <SnapConsentHandoffFlow {...props} theme={brand} />;
56
+ ```
57
+
58
+ `DEFAULT_SNAP_CONSENT_THEME` and `resolveSnapConsentTheme` are exported if you need to merge or inspect defaults in app code.
59
+
60
+ ## Imperative opener (recommended for modals)
61
+
62
+ ```tsx
63
+ import { openSnapConsentHandoffFlow } from "@snapkyc/consent-handoff-react";
64
+ import "@snapkyc/consent-handoff-react/styles.css";
65
+
66
+ const { dispose } = openSnapConsentHandoffFlow({
67
+ integrationToken,
68
+ rpContext: { reference_id: user.id, session_id },
69
+ /** Select exactly one post-initiation path — never both */
70
+ handoffMode: "qr", // or "intent"
71
+ /** Optional tweaks */
72
+ pollIntervalMs: 1500,
73
+ pollDeadlineMs: 120_000,
74
+ onFlowEvent(e) {},
75
+ onSuccess(result) {},
76
+ onError(err) {},
77
+ });
78
+
79
+ // On route change / unmount caller context
80
+ dispose();
81
+ ```
82
+
83
+ `openSnapConsentQrFlow` is a **deprecated alias** of the same function.
84
+
85
+ ### Intent platform detection
86
+
87
+ With `handoffMode: "intent"`, the SDK infers **`android`** vs **`ios`** from the browser UA. If ambiguous (typical desktop browser), users pick **Continue with Android** or **Continue with iPhone/iPad**. For automated tests only, set `_dangerouslyForceIntentPlatform`.
88
+
89
+ ## Declarative
90
+
91
+ On the consent step, the primary action is labelled **I Agree** (with **Cancel** beside it to dismiss). After a successful verification, **Done** dismisses the flow the same way as the modal close control.
92
+
93
+ ```tsx
94
+ import { SnapConsentHandoffFlow } from "@snapkyc/consent-handoff-react";
95
+ import "@snapkyc/consent-handoff-react/styles.css";
96
+
97
+ <SnapConsentHandoffFlow
98
+ integrationToken={token}
99
+ rpContext={{ reference_id, session_id }}
100
+ handoffMode="intent"
101
+ displayMode="inline"
102
+ />;
103
+ ```
104
+
105
+ ## Props (summary)
106
+
107
+ | Prop | Purpose |
108
+ |------|---------|
109
+ | `integrationToken` | Sent as `Authorization: Token …` on every request |
110
+ | `rpContext.reference_id` | Sent as `rp_context.ref_id` on `POST …/transactions/initiate` |
111
+ | `handoffMode` | `"qr"` → `POST …/generate-qr` (PNG). `"intent"` → `POST …/generate-intent?platform=` |
112
+ | `agreementId?` | Reserved; agreement is implied by the integration token |
113
+ | `acceptLanguage?` | `Accept-Language` + preference for `agreement_text` locale |
114
+ | `qrRequestBody?` | QR overrides (`size`; `txn_id` is set by the SDK) |
115
+ | `pollIntervalMs` / `pollDeadlineMs` | Polling behaviour after handoff |
116
+ | `theme?` | Partial palette / layout overrides (see **Theme**) |
117
+ | `onRequestClose?` | Called when the user closes the modal (**×**), taps **Cancel** on the consent step, or taps **Done** after success. With `openSnapConsentHandoffFlow`, this is wired to `dispose()`. If omitted (e.g. inline embed), the SDK hides its own UI after those actions. |
118
+
119
+ ## Credential hygiene
120
+
121
+ `integrationToken` is a bearer credential in the browser. Prefer short-lived minted tokens from your backend rather than embedding long-lived secrets in static bundles.
122
+
123
+ ## Publishing / environments
124
+
125
+ Bump `API_ORIGIN` when cutting staging/production builds (fork your publish pipeline per environment or maintain separate semver lines).
126
+
127
+ ### npm: `E404` — “Scope not found” (`@snapkyc/...`)
128
+
129
+ Scoped packages like **`@snapkyc/consent-handoff-react`** can only be published if the **scope exists on npm** and **your logged-in user is allowed to publish** to it.
130
+
131
+ **Option A — use the `snapkyc` org (intended for SnapKYC)**
132
+
133
+ 1. An org owner creates **[`snapkyc` on npm](https://www.npmjs.com/org/create)** (if it does not exist yet).
134
+ 2. They invite your npm user with a role that can **publish** (e.g. member with publish, or owner).
135
+ 3. You accept the invite, then run `npm login` and `npm publish --access public` again.
136
+
137
+ **Option B — publish under your own scope**
138
+
139
+ 1. Change the `"name"` field in `package.json` to a scope you control, e.g. `"@<your-npm-username>/consent-handoff-react"`.
140
+ 2. Bump the version if you already published under another name, then `npm publish --access public`.
141
+
142
+ **Option C — unscoped package**
143
+
144
+ Use a unique unscoped name (e.g. `snapkyc-consent-handoff-react`) in `"name"` if you do not use npm orgs. Check name availability on [npmjs.com](https://www.npmjs.com/).
145
+
146
+ After any rename, update install instructions and all `import` paths for consumers.
147
+
148
+ ## Develop
149
+
150
+ ```bash
151
+ npm install
152
+ npm test
153
+ npm run build
154
+ ```
155
+
156
+ ## License
157
+
158
+ MIT