@netlib/widerrufsbutton 1.0.5 → 1.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 +9 -9
- package/dist/fallback.d.ts +8 -0
- package/dist/index.cjs.js +126 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.es.js +273 -107
- package/dist/styles.d.ts +1 -0
- package/dist/types.d.ts +15 -1
- package/dist/widerruf.html +323 -0
- package/dist/widerrufsbutton.iife.js +29 -10
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Widerrufsformular einbettbares JavaScript-Widget (React + TypeScript, IIFE-Build
|
|
|
4
4
|
|
|
5
5
|
## Rechtliche Grundlage
|
|
6
6
|
|
|
7
|
-
Pflichtfelder
|
|
7
|
+
Pflichtfelder:
|
|
8
8
|
- **Name** des Verbrauchers
|
|
9
9
|
- **E-Mail-Adresse** (für die gesetzlich vorgeschriebene Eingangsbestätigung)
|
|
10
10
|
- **Bestell- / Auftrags- / Vertragsnummer** (Vertragsidentifikation)
|
|
@@ -57,24 +57,24 @@ Content-Type: application/json
|
|
|
57
57
|
|
|
58
58
|
## Konfigurationsparameter
|
|
59
59
|
|
|
60
|
-
| Parameter
|
|
61
|
-
|
|
62
|
-
| `apiUrl`
|
|
63
|
-
| `action`
|
|
64
|
-
| `introText`
|
|
60
|
+
| Parameter | Typ | Pflicht | Beschreibung |
|
|
61
|
+
|---------------|---|---|---|
|
|
62
|
+
| `apiUrl` | string | ja | PATCH-Endpunkt |
|
|
63
|
+
| `action` | string | ja | Action-Name, Default: `widerruf_submit` |
|
|
64
|
+
| `introText` | string | – | Einleitungstext im Modal |
|
|
65
65
|
| `companyName` | string | – | Firmenname im Modal-Titel |
|
|
66
66
|
| `buttonLabel` | string | – | Button-Beschriftung, Default: `Vertrag widerrufen` |
|
|
67
67
|
| `cancelLabel` | string | – | Abbrechen-Button, Default: `Abbrechen` |
|
|
68
68
|
| `submitLabel` | string | – | Absenden-Button, Default: `Widerruf bestätigen` |
|
|
69
69
|
| `buttonClass` | string | – | Zusätzliche CSS-Klassen am Button |
|
|
70
|
-
| `
|
|
70
|
+
| `cl` | string | – | Bearer-Token für `Authorization`-Header |
|
|
71
71
|
|
|
72
72
|
## Einbindung
|
|
73
73
|
|
|
74
74
|
### Option A – React / Astro
|
|
75
75
|
|
|
76
76
|
```tsx
|
|
77
|
-
import { WiderrufsWidget } from '@netlib
|
|
77
|
+
import { WiderrufsWidget } from '@netlib/widerrufsbutton'
|
|
78
78
|
|
|
79
79
|
<WiderrufsWidget config={{
|
|
80
80
|
apiUrl: 'https://example.com/api',
|
|
@@ -84,7 +84,7 @@ import { WiderrufsWidget } from '@netlib-de/widerrufsbutton'
|
|
|
84
84
|
}} />
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
-
### Option B – IIFE / Data-Attribute (kein Framework nötig)
|
|
87
|
+
### Option B – IIFE / Data-Attribute (kein Framework nötig) but
|
|
88
88
|
|
|
89
89
|
```html
|
|
90
90
|
<script src="widerrufsbutton.iife.js" defer></script>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { WiderrufsConfig } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Generates a complete, self-contained HTML page for the Widerruf form.
|
|
4
|
+
* Works without JavaScript — the form submits via POST to config.formAction (or config.apiUrl).
|
|
5
|
+
* Integrators embed this via generateFallbackHtml(config) in Astro or serve the pre-built
|
|
6
|
+
* dist/widerruf.html from any web server (ColdFusion, nginx, etc.).
|
|
7
|
+
*/
|
|
8
|
+
export declare function generateFallbackHtml(config: WiderrufsConfig): string;
|
package/dist/index.cjs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("react/jsx-runtime"),b=require("react"),C=require("react-dom");async function L(e,t){const n={"Content-Type":"application/json"};e.authToken&&(n.Authorization=`Bearer ${e.authToken}`);const d={action:e.action,payload:{...t,datum:new Date().toISOString()}},i=await fetch(e.apiUrl,{method:"PATCH",headers:n,body:JSON.stringify(d)});let l;try{l=await i.json()}catch{if(!i.ok)throw new Error(`Server antwortete mit Status ${i.status}`);return}if(l!==null&&typeof l=="object"&&"ok"in l&&l.ok===!1){const s=l.message;throw new Error(typeof s=="string"&&s?s:`Server antwortete mit Status ${i.status}`)}if(!i.ok)throw new Error(`Server antwortete mit Status ${i.status}`)}const z=new Date().toLocaleDateString("de-DE",{day:"2-digit",month:"2-digit",year:"numeric"}),T={name:"",email:"",vertragId:"",widerrufsgrund:"",datum:z};function j(e){const t={};return e.name.trim()||(t.name="Bitte geben Sie Ihren Namen an."),e.email.trim()?/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e.email)||(t.email="Bitte geben Sie eine gültige E-Mail-Adresse an."):t.email="Bitte geben Sie Ihre E-Mail-Adresse an.",e.vertragId.trim()||(t.vertragId="Bitte geben Sie die Bestellnummer oder Vertragsnummer an."),t}function W({config:e,onClose:t}){const[n,d]=b.useState(T),[i,l]=b.useState({}),[s,p]=b.useState({}),[x,y]=b.useState("idle"),[k,N]=b.useState(""),S=b.useRef(null);b.useEffect(()=>{var c;(c=S.current)==null||c.focus();const a=o=>o.key==="Escape"&&t();return document.addEventListener("keydown",a),()=>document.removeEventListener("keydown",a)},[t]);function w(a,c){const o={...n,[a]:c};if(d(o),s[a]){const h=j(o);l(g=>({...g,[a]:h[a]}))}}function v(a){p(o=>({...o,[a]:!0}));const c=j(n);l(o=>({...o,[a]:c[a]}))}async function I(a){var h,g;a.preventDefault();const c=Object.fromEntries(Object.keys(n).map(f=>[f,!0]));p(c);const o=j(n);if(l(o),!(Object.keys(o).length>0)){y("loading"),N("");try{await L(e,n),y("success"),(h=e.onSuccess)==null||h.call(e)}catch(f){const E=f instanceof Error?f:new Error("Ein unbekannter Fehler ist aufgetreten.");N(E.message),y("error"),(g=e.onError)==null||g.call(e,E)}}}const A=e.companyName?`Widerruf – ${e.companyName}`:"Widerrufsformular";return r.jsx("div",{className:"wrb-overlay",role:"dialog","aria-modal":"true","aria-labelledby":"wrb-title",onClick:a=>a.target===a.currentTarget&&t(),children:r.jsxs("div",{className:"wrb-modal",children:[r.jsxs("div",{className:"wrb-modal-header",children:[r.jsx("h2",{className:"wrb-modal-title",id:"wrb-title",children:A}),r.jsx("button",{className:"wrb-close-btn",onClick:t,"aria-label":"Schließen",type:"button",children:"✕"})]}),x==="success"?r.jsxs("div",{className:"wrb-modal-body",children:[r.jsxs("div",{className:"wrb-success",children:[r.jsx("span",{className:"wrb-success-icon",children:"✓"}),r.jsx("h3",{children:"Widerruf eingegangen"}),r.jsxs("p",{children:["Ihr Widerruf wurde erfolgreich übermittelt. Sie erhalten in Kürze eine Bestätigung an ",r.jsx("strong",{children:n.email}),"."]})]}),r.jsx($,{links:e.legalLinks})]}):r.jsxs("div",{className:"wrb-modal-body",children:[e.introText&&r.jsx("p",{className:"wrb-intro",children:e.introText}),x==="error"&&k&&r.jsx("div",{className:"wrb-alert wrb-alert-error",role:"alert",children:k}),r.jsxs("form",{onSubmit:I,noValidate:!0,children:[r.jsx(m,{label:"Name",required:!0,error:s.name?i.name:void 0,children:r.jsx("input",{ref:S,className:`wrb-input${s.name&&i.name?" wrb-error":""}`,type:"text",autoComplete:"name",value:n.name,onChange:a=>w("name",a.target.value),onBlur:()=>v("name"),placeholder:"Vor- und Nachname"})}),r.jsx(m,{label:"E-Mail-Adresse",required:!0,hint:"Hierüber erhalten Sie die Eingangsbestätigung.",error:s.email?i.email:void 0,children:r.jsx("input",{className:`wrb-input${s.email&&i.email?" wrb-error":""}`,type:"email",autoComplete:"email",value:n.email,onChange:a=>w("email",a.target.value),onBlur:()=>v("email"),placeholder:"name@beispiel.de"})}),r.jsx(m,{label:"Bestell- / Auftrags- / Vertragsnummer",required:!0,hint:"Zu finden in Ihrer Bestellbestätigung.",error:s.vertragId?i.vertragId:void 0,children:r.jsx("input",{className:`wrb-input${s.vertragId&&i.vertragId?" wrb-error":""}`,type:"text",value:n.vertragId,onChange:a=>w("vertragId",a.target.value),onBlur:()=>v("vertragId"),placeholder:"z.B. 10045678"})}),r.jsx(m,{label:"Widerrufsgrund",hint:"Freiwillige Angabe – ein Widerruf ist ohne Angabe von Gründen möglich.",children:r.jsx("textarea",{className:"wrb-textarea",value:n.widerrufsgrund,onChange:a=>w("widerrufsgrund",a.target.value),placeholder:"Optional",rows:3})}),r.jsx(m,{label:"Datum der Widerrufserklärung",children:r.jsx("div",{className:"wrb-date-display",children:z})}),r.jsxs("div",{className:"wrb-actions",children:[r.jsx("button",{type:"button",className:"wrb-cancel-btn",onClick:t,children:e.cancelLabel??"Abbrechen"}),r.jsx("button",{type:"submit",className:"wrb-submit-btn",disabled:x==="loading",children:x==="loading"?"Wird gesendet…":e.submitLabel??"Absenden"})]})]}),r.jsx($,{links:e.legalLinks})]})]})})}function m({label:e,required:t,hint:n,error:d,children:i}){return r.jsxs("div",{className:"wrb-field",children:[r.jsxs("label",{className:"wrb-label",children:[e,t&&r.jsx("span",{className:"wrb-required","aria-hidden":"true",children:"*"})]}),i,n&&!d&&r.jsx("p",{className:"wrb-hint",children:n}),d&&r.jsx("p",{className:"wrb-field-error",role:"alert",children:d})]})}function $({links:e}){return e!=null&&e.length?r.jsx("div",{className:"wrb-legal-links",children:e.map(t=>r.jsx("a",{href:t.href,className:"wrb-legal-link",target:"_blank",rel:"noopener noreferrer",children:t.name},t.href))}):null}const B=`
|
|
2
2
|
/* Widerrufsbutton widget — prefix: wrb- */
|
|
3
3
|
.wrb-btn {
|
|
4
4
|
display: inline-flex;
|
|
@@ -200,4 +200,128 @@
|
|
|
200
200
|
font-size: 14px;
|
|
201
201
|
}
|
|
202
202
|
.wrb-alert-error { background: #fef2f2; border: 1px solid #fecaca; color: #991b1b; }
|
|
203
|
-
|
|
203
|
+
|
|
204
|
+
/* Legal links */
|
|
205
|
+
.wrb-legal-links {
|
|
206
|
+
display: flex;
|
|
207
|
+
flex-wrap: wrap;
|
|
208
|
+
gap: 4px 16px;
|
|
209
|
+
margin-top: 16px;
|
|
210
|
+
padding-top: 12px;
|
|
211
|
+
border-top: 1px solid #e5e7eb;
|
|
212
|
+
}
|
|
213
|
+
.wrb-legal-link {
|
|
214
|
+
font-size: 12px;
|
|
215
|
+
color: #6b7280;
|
|
216
|
+
text-decoration: none;
|
|
217
|
+
}
|
|
218
|
+
.wrb-legal-link:hover {
|
|
219
|
+
color: #374151;
|
|
220
|
+
text-decoration: underline;
|
|
221
|
+
}
|
|
222
|
+
`;function q(){const e="wrb-styles";if(document.getElementById(e))return;const t=document.createElement("style");t.id=e,t.textContent=B,document.head.appendChild(t)}function O({config:e}){const[t,n]=b.useState(!1);return b.useEffect(()=>{q()},[]),r.jsxs(r.Fragment,{children:[r.jsx("button",{type:"button",className:`wrb-btn${e.buttonClass?` ${e.buttonClass}`:""}`,onClick:()=>n(!0),children:e.buttonLabel??"Vertrag widerrufen"}),t&&C.createPortal(r.jsx(W,{config:e,onClose:()=>n(!1)}),document.body)]})}function u(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function D(e){var s;const t=new Date().toLocaleDateString("de-DE",{day:"2-digit",month:"2-digit",year:"numeric"}),n=e.companyName?`Widerruf – ${u(e.companyName)}`:"Widerrufsformular",d=u(e.formAction??e.apiUrl??"/rest/v1/apiCancellation"),i=e.introText?`<p class="wrb-intro">${u(e.introText)}</p>`:"",l=(s=e.legalLinks)!=null&&s.length?`
|
|
223
|
+
<div class="wrb-legal-links">
|
|
224
|
+
${e.legalLinks.map(p=>`<a href="${u(p.href)}" class="wrb-legal-link" rel="noopener noreferrer">${u(p.name)}</a>`).join(`
|
|
225
|
+
`)}
|
|
226
|
+
</div>`:"";return`<!DOCTYPE html>
|
|
227
|
+
<html lang="de">
|
|
228
|
+
<head>
|
|
229
|
+
<meta charset="UTF-8">
|
|
230
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
231
|
+
<title>${n}</title>
|
|
232
|
+
<style>
|
|
233
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
234
|
+
body { margin: 0; background: #f9fafb; }
|
|
235
|
+
.wrb-page {
|
|
236
|
+
min-height: 100vh;
|
|
237
|
+
display: flex;
|
|
238
|
+
align-items: flex-start;
|
|
239
|
+
justify-content: center;
|
|
240
|
+
padding: 40px 16px;
|
|
241
|
+
}
|
|
242
|
+
.wrb-page .wrb-modal { max-height: none; }
|
|
243
|
+
.wrb-page .wrb-modal-title { font-size: 20px; }
|
|
244
|
+
${B}
|
|
245
|
+
</style>
|
|
246
|
+
</head>
|
|
247
|
+
<body>
|
|
248
|
+
<div class="wrb-page">
|
|
249
|
+
<div class="wrb-modal">
|
|
250
|
+
<div class="wrb-modal-header">
|
|
251
|
+
<h1 class="wrb-modal-title">${n}</h1>
|
|
252
|
+
</div>
|
|
253
|
+
<div class="wrb-modal-body">
|
|
254
|
+
${i}
|
|
255
|
+
<form method="POST" action="${d}" novalidate>
|
|
256
|
+
<div class="wrb-field">
|
|
257
|
+
<label class="wrb-label">
|
|
258
|
+
Name <span class="wrb-required" aria-hidden="true">*</span>
|
|
259
|
+
</label>
|
|
260
|
+
<input
|
|
261
|
+
class="wrb-input"
|
|
262
|
+
type="text"
|
|
263
|
+
name="name"
|
|
264
|
+
autocomplete="name"
|
|
265
|
+
placeholder="Vor- und Nachname"
|
|
266
|
+
required
|
|
267
|
+
>
|
|
268
|
+
</div>
|
|
269
|
+
<div class="wrb-field">
|
|
270
|
+
<label class="wrb-label">
|
|
271
|
+
E-Mail-Adresse <span class="wrb-required" aria-hidden="true">*</span>
|
|
272
|
+
</label>
|
|
273
|
+
<input
|
|
274
|
+
class="wrb-input"
|
|
275
|
+
type="email"
|
|
276
|
+
name="email"
|
|
277
|
+
autocomplete="email"
|
|
278
|
+
placeholder="name@beispiel.de"
|
|
279
|
+
required
|
|
280
|
+
>
|
|
281
|
+
<p class="wrb-hint">Hierüber erhalten Sie die Eingangsbestätigung.</p>
|
|
282
|
+
</div>
|
|
283
|
+
<div class="wrb-field">
|
|
284
|
+
<label class="wrb-label">
|
|
285
|
+
Bestell- / Auftrags- / Vertragsnummer
|
|
286
|
+
<span class="wrb-required" aria-hidden="true">*</span>
|
|
287
|
+
</label>
|
|
288
|
+
<input
|
|
289
|
+
class="wrb-input"
|
|
290
|
+
type="text"
|
|
291
|
+
name="vertragId"
|
|
292
|
+
placeholder="z.B. 10045678"
|
|
293
|
+
required
|
|
294
|
+
>
|
|
295
|
+
<p class="wrb-hint">Zu finden in Ihrer Bestellbestätigung.</p>
|
|
296
|
+
</div>
|
|
297
|
+
<div class="wrb-field">
|
|
298
|
+
<label class="wrb-label">Widerrufsgrund</label>
|
|
299
|
+
<textarea
|
|
300
|
+
class="wrb-textarea"
|
|
301
|
+
name="widerrufsgrund"
|
|
302
|
+
placeholder="Optional"
|
|
303
|
+
rows="3"
|
|
304
|
+
></textarea>
|
|
305
|
+
<p class="wrb-hint">
|
|
306
|
+
Freiwillige Angabe – ein Widerruf ist ohne Angabe von Gründen möglich.
|
|
307
|
+
</p>
|
|
308
|
+
</div>
|
|
309
|
+
<div class="wrb-field">
|
|
310
|
+
<label class="wrb-label">Datum der Widerrufserklärung</label>
|
|
311
|
+
<div class="wrb-date-display">${t}</div>
|
|
312
|
+
<input type="hidden" name="datum" value="${t}">
|
|
313
|
+
</div>
|
|
314
|
+
<input type="hidden" name="action" value="${u(e.action)}">
|
|
315
|
+
${e.successUrl?`<input type="hidden" name="successUrl" value="${u(e.successUrl)}">`:""}
|
|
316
|
+
<div class="wrb-actions">
|
|
317
|
+
<button type="submit" class="wrb-submit-btn">
|
|
318
|
+
${u(e.submitLabel??"Absenden")}
|
|
319
|
+
</button>
|
|
320
|
+
</div>
|
|
321
|
+
</form>
|
|
322
|
+
${l}
|
|
323
|
+
</div>
|
|
324
|
+
</div>
|
|
325
|
+
</div>
|
|
326
|
+
</body>
|
|
327
|
+
</html>`}exports.WiderrufsModal=W;exports.WiderrufsWidget=O;exports.generateFallbackHtml=D;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { WiderrufsWidget } from './components/WiderrufsWidget';
|
|
2
2
|
export { WiderrufsModal } from './components/WiderrufsModal';
|
|
3
|
-
export
|
|
3
|
+
export { generateFallbackHtml } from './fallback';
|
|
4
|
+
export type { WiderrufsConfig, WiderrufsFormData, SubmitStatus, LegalLink } from './types';
|