@sendmailos/sdk 1.0.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/LICENSE +21 -0
- package/README.md +204 -0
- package/dist/index.d.mts +480 -0
- package/dist/index.d.ts +480 -0
- package/dist/index.js +538 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +525 -0
- package/dist/index.mjs.map +1 -0
- package/dist/react/index.d.mts +140 -0
- package/dist/react/index.d.ts +140 -0
- package/dist/react/index.js +228 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/index.mjs +223 -0
- package/dist/react/index.mjs.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
interface SendMailOSContextValue {
|
|
5
|
+
publicKey: string;
|
|
6
|
+
baseUrl: string;
|
|
7
|
+
}
|
|
8
|
+
interface SendMailOSProviderProps {
|
|
9
|
+
/** Your public key (pk_live_... or pk_test_...) */
|
|
10
|
+
publicKey: string;
|
|
11
|
+
/** Custom API base URL (optional) */
|
|
12
|
+
baseUrl?: string;
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Provider component for SendMailOS React integration
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* import { SendMailOSProvider } from '@sendmailos/sdk/react';
|
|
21
|
+
*
|
|
22
|
+
* function App() {
|
|
23
|
+
* return (
|
|
24
|
+
* <SendMailOSProvider publicKey="pk_live_...">
|
|
25
|
+
* <YourApp />
|
|
26
|
+
* </SendMailOSProvider>
|
|
27
|
+
* );
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
declare function SendMailOSProvider({ publicKey, baseUrl, children, }: SendMailOSProviderProps): react_jsx_runtime.JSX.Element;
|
|
32
|
+
/**
|
|
33
|
+
* Hook to access SendMailOS context
|
|
34
|
+
*/
|
|
35
|
+
declare function useSendMailOS(): SendMailOSContextValue;
|
|
36
|
+
|
|
37
|
+
interface SubscribeParams {
|
|
38
|
+
email: string;
|
|
39
|
+
firstName?: string;
|
|
40
|
+
lastName?: string;
|
|
41
|
+
tags?: string[];
|
|
42
|
+
}
|
|
43
|
+
interface SubscribeResult {
|
|
44
|
+
success: boolean;
|
|
45
|
+
subscriberId?: string;
|
|
46
|
+
message?: string;
|
|
47
|
+
}
|
|
48
|
+
interface UseSubscribeReturn {
|
|
49
|
+
/** Subscribe a new email address */
|
|
50
|
+
subscribe: (params: SubscribeParams) => Promise<SubscribeResult>;
|
|
51
|
+
/** Loading state */
|
|
52
|
+
isLoading: boolean;
|
|
53
|
+
/** Error message if subscription failed */
|
|
54
|
+
error: Error | null;
|
|
55
|
+
/** Success state */
|
|
56
|
+
isSuccess: boolean;
|
|
57
|
+
/** Reset the hook state */
|
|
58
|
+
reset: () => void;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Hook for subscribing users to your email list
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```tsx
|
|
65
|
+
* function NewsletterForm() {
|
|
66
|
+
* const { subscribe, isLoading, error, isSuccess } = useSubscribe();
|
|
67
|
+
* const [email, setEmail] = useState('');
|
|
68
|
+
*
|
|
69
|
+
* const handleSubmit = async (e) => {
|
|
70
|
+
* e.preventDefault();
|
|
71
|
+
* await subscribe({ email, tags: ['newsletter'] });
|
|
72
|
+
* };
|
|
73
|
+
*
|
|
74
|
+
* if (isSuccess) {
|
|
75
|
+
* return <p>Thanks for subscribing!</p>;
|
|
76
|
+
* }
|
|
77
|
+
*
|
|
78
|
+
* return (
|
|
79
|
+
* <form onSubmit={handleSubmit}>
|
|
80
|
+
* <input
|
|
81
|
+
* type="email"
|
|
82
|
+
* value={email}
|
|
83
|
+
* onChange={(e) => setEmail(e.target.value)}
|
|
84
|
+
* placeholder="Enter your email"
|
|
85
|
+
* />
|
|
86
|
+
* <button disabled={isLoading}>
|
|
87
|
+
* {isLoading ? 'Subscribing...' : 'Subscribe'}
|
|
88
|
+
* </button>
|
|
89
|
+
* {error && <p>{error.message}</p>}
|
|
90
|
+
* </form>
|
|
91
|
+
* );
|
|
92
|
+
* }
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
declare function useSubscribe(): UseSubscribeReturn;
|
|
96
|
+
|
|
97
|
+
interface SubscribeFormProps {
|
|
98
|
+
/** Tags to apply to new subscribers */
|
|
99
|
+
tags?: string[];
|
|
100
|
+
/** Callback when subscription succeeds */
|
|
101
|
+
onSuccess?: () => void;
|
|
102
|
+
/** Callback when subscription fails */
|
|
103
|
+
onError?: (error: Error) => void;
|
|
104
|
+
/** CSS class for the form container */
|
|
105
|
+
className?: string;
|
|
106
|
+
/** Placeholder text for email input */
|
|
107
|
+
placeholder?: string;
|
|
108
|
+
/** Text for submit button */
|
|
109
|
+
buttonText?: string;
|
|
110
|
+
/** Text shown while loading */
|
|
111
|
+
loadingText?: string;
|
|
112
|
+
/** Text shown on success */
|
|
113
|
+
successMessage?: string;
|
|
114
|
+
/** Whether to show first/last name fields */
|
|
115
|
+
showNameFields?: boolean;
|
|
116
|
+
/** Custom styles */
|
|
117
|
+
style?: React.CSSProperties;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Pre-built newsletter subscription form
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```tsx
|
|
124
|
+
* import { SubscribeForm } from '@sendmailos/sdk/react';
|
|
125
|
+
*
|
|
126
|
+
* function Newsletter() {
|
|
127
|
+
* return (
|
|
128
|
+
* <SubscribeForm
|
|
129
|
+
* tags={['newsletter']}
|
|
130
|
+
* onSuccess={() => console.log('Subscribed!')}
|
|
131
|
+
* buttonText="Join Newsletter"
|
|
132
|
+
* placeholder="you@example.com"
|
|
133
|
+
* />
|
|
134
|
+
* );
|
|
135
|
+
* }
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
declare function SubscribeForm({ tags, onSuccess, onError, className, placeholder, buttonText, loadingText, successMessage, showNameFields, style, }: SubscribeFormProps): react_jsx_runtime.JSX.Element;
|
|
139
|
+
|
|
140
|
+
export { SendMailOSProvider, SubscribeForm, type SubscribeFormProps, useSendMailOS, useSubscribe };
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
interface SendMailOSContextValue {
|
|
5
|
+
publicKey: string;
|
|
6
|
+
baseUrl: string;
|
|
7
|
+
}
|
|
8
|
+
interface SendMailOSProviderProps {
|
|
9
|
+
/** Your public key (pk_live_... or pk_test_...) */
|
|
10
|
+
publicKey: string;
|
|
11
|
+
/** Custom API base URL (optional) */
|
|
12
|
+
baseUrl?: string;
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Provider component for SendMailOS React integration
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* import { SendMailOSProvider } from '@sendmailos/sdk/react';
|
|
21
|
+
*
|
|
22
|
+
* function App() {
|
|
23
|
+
* return (
|
|
24
|
+
* <SendMailOSProvider publicKey="pk_live_...">
|
|
25
|
+
* <YourApp />
|
|
26
|
+
* </SendMailOSProvider>
|
|
27
|
+
* );
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
declare function SendMailOSProvider({ publicKey, baseUrl, children, }: SendMailOSProviderProps): react_jsx_runtime.JSX.Element;
|
|
32
|
+
/**
|
|
33
|
+
* Hook to access SendMailOS context
|
|
34
|
+
*/
|
|
35
|
+
declare function useSendMailOS(): SendMailOSContextValue;
|
|
36
|
+
|
|
37
|
+
interface SubscribeParams {
|
|
38
|
+
email: string;
|
|
39
|
+
firstName?: string;
|
|
40
|
+
lastName?: string;
|
|
41
|
+
tags?: string[];
|
|
42
|
+
}
|
|
43
|
+
interface SubscribeResult {
|
|
44
|
+
success: boolean;
|
|
45
|
+
subscriberId?: string;
|
|
46
|
+
message?: string;
|
|
47
|
+
}
|
|
48
|
+
interface UseSubscribeReturn {
|
|
49
|
+
/** Subscribe a new email address */
|
|
50
|
+
subscribe: (params: SubscribeParams) => Promise<SubscribeResult>;
|
|
51
|
+
/** Loading state */
|
|
52
|
+
isLoading: boolean;
|
|
53
|
+
/** Error message if subscription failed */
|
|
54
|
+
error: Error | null;
|
|
55
|
+
/** Success state */
|
|
56
|
+
isSuccess: boolean;
|
|
57
|
+
/** Reset the hook state */
|
|
58
|
+
reset: () => void;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Hook for subscribing users to your email list
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```tsx
|
|
65
|
+
* function NewsletterForm() {
|
|
66
|
+
* const { subscribe, isLoading, error, isSuccess } = useSubscribe();
|
|
67
|
+
* const [email, setEmail] = useState('');
|
|
68
|
+
*
|
|
69
|
+
* const handleSubmit = async (e) => {
|
|
70
|
+
* e.preventDefault();
|
|
71
|
+
* await subscribe({ email, tags: ['newsletter'] });
|
|
72
|
+
* };
|
|
73
|
+
*
|
|
74
|
+
* if (isSuccess) {
|
|
75
|
+
* return <p>Thanks for subscribing!</p>;
|
|
76
|
+
* }
|
|
77
|
+
*
|
|
78
|
+
* return (
|
|
79
|
+
* <form onSubmit={handleSubmit}>
|
|
80
|
+
* <input
|
|
81
|
+
* type="email"
|
|
82
|
+
* value={email}
|
|
83
|
+
* onChange={(e) => setEmail(e.target.value)}
|
|
84
|
+
* placeholder="Enter your email"
|
|
85
|
+
* />
|
|
86
|
+
* <button disabled={isLoading}>
|
|
87
|
+
* {isLoading ? 'Subscribing...' : 'Subscribe'}
|
|
88
|
+
* </button>
|
|
89
|
+
* {error && <p>{error.message}</p>}
|
|
90
|
+
* </form>
|
|
91
|
+
* );
|
|
92
|
+
* }
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
declare function useSubscribe(): UseSubscribeReturn;
|
|
96
|
+
|
|
97
|
+
interface SubscribeFormProps {
|
|
98
|
+
/** Tags to apply to new subscribers */
|
|
99
|
+
tags?: string[];
|
|
100
|
+
/** Callback when subscription succeeds */
|
|
101
|
+
onSuccess?: () => void;
|
|
102
|
+
/** Callback when subscription fails */
|
|
103
|
+
onError?: (error: Error) => void;
|
|
104
|
+
/** CSS class for the form container */
|
|
105
|
+
className?: string;
|
|
106
|
+
/** Placeholder text for email input */
|
|
107
|
+
placeholder?: string;
|
|
108
|
+
/** Text for submit button */
|
|
109
|
+
buttonText?: string;
|
|
110
|
+
/** Text shown while loading */
|
|
111
|
+
loadingText?: string;
|
|
112
|
+
/** Text shown on success */
|
|
113
|
+
successMessage?: string;
|
|
114
|
+
/** Whether to show first/last name fields */
|
|
115
|
+
showNameFields?: boolean;
|
|
116
|
+
/** Custom styles */
|
|
117
|
+
style?: React.CSSProperties;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Pre-built newsletter subscription form
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```tsx
|
|
124
|
+
* import { SubscribeForm } from '@sendmailos/sdk/react';
|
|
125
|
+
*
|
|
126
|
+
* function Newsletter() {
|
|
127
|
+
* return (
|
|
128
|
+
* <SubscribeForm
|
|
129
|
+
* tags={['newsletter']}
|
|
130
|
+
* onSuccess={() => console.log('Subscribed!')}
|
|
131
|
+
* buttonText="Join Newsletter"
|
|
132
|
+
* placeholder="you@example.com"
|
|
133
|
+
* />
|
|
134
|
+
* );
|
|
135
|
+
* }
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
declare function SubscribeForm({ tags, onSuccess, onError, className, placeholder, buttonText, loadingText, successMessage, showNameFields, style, }: SubscribeFormProps): react_jsx_runtime.JSX.Element;
|
|
139
|
+
|
|
140
|
+
export { SendMailOSProvider, SubscribeForm, type SubscribeFormProps, useSendMailOS, useSubscribe };
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
|
|
6
|
+
// src/react/provider.tsx
|
|
7
|
+
var SendMailOSContext = react.createContext(null);
|
|
8
|
+
function SendMailOSProvider({
|
|
9
|
+
publicKey,
|
|
10
|
+
baseUrl = "https://api.sendmailos.com/api/v1",
|
|
11
|
+
children
|
|
12
|
+
}) {
|
|
13
|
+
if (!publicKey) {
|
|
14
|
+
throw new Error("SendMailOSProvider requires a publicKey");
|
|
15
|
+
}
|
|
16
|
+
if (!publicKey.startsWith("pk_")) {
|
|
17
|
+
console.warn(
|
|
18
|
+
'[SendMailOS] Public keys should start with "pk_". Never expose secret keys (sk_) in client-side code.'
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
const value = react.useMemo(
|
|
22
|
+
() => ({
|
|
23
|
+
publicKey,
|
|
24
|
+
baseUrl: baseUrl.replace(/\/$/, "")
|
|
25
|
+
}),
|
|
26
|
+
[publicKey, baseUrl]
|
|
27
|
+
);
|
|
28
|
+
return /* @__PURE__ */ jsxRuntime.jsx(SendMailOSContext.Provider, { value, children });
|
|
29
|
+
}
|
|
30
|
+
function useSendMailOS() {
|
|
31
|
+
const context = react.useContext(SendMailOSContext);
|
|
32
|
+
if (!context) {
|
|
33
|
+
throw new Error("useSendMailOS must be used within a SendMailOSProvider");
|
|
34
|
+
}
|
|
35
|
+
return context;
|
|
36
|
+
}
|
|
37
|
+
function useSubscribe() {
|
|
38
|
+
const { publicKey, baseUrl } = useSendMailOS();
|
|
39
|
+
const [isLoading, setIsLoading] = react.useState(false);
|
|
40
|
+
const [error, setError] = react.useState(null);
|
|
41
|
+
const [isSuccess, setIsSuccess] = react.useState(false);
|
|
42
|
+
const reset = react.useCallback(() => {
|
|
43
|
+
setIsLoading(false);
|
|
44
|
+
setError(null);
|
|
45
|
+
setIsSuccess(false);
|
|
46
|
+
}, []);
|
|
47
|
+
const subscribe = react.useCallback(
|
|
48
|
+
async (params) => {
|
|
49
|
+
setIsLoading(true);
|
|
50
|
+
setError(null);
|
|
51
|
+
setIsSuccess(false);
|
|
52
|
+
try {
|
|
53
|
+
const response = await fetch(`${baseUrl}/public/subscribe`, {
|
|
54
|
+
method: "POST",
|
|
55
|
+
headers: {
|
|
56
|
+
"Content-Type": "application/json",
|
|
57
|
+
"X-Public-Key": publicKey
|
|
58
|
+
},
|
|
59
|
+
body: JSON.stringify({
|
|
60
|
+
email: params.email,
|
|
61
|
+
first_name: params.firstName,
|
|
62
|
+
last_name: params.lastName,
|
|
63
|
+
tags: params.tags
|
|
64
|
+
})
|
|
65
|
+
});
|
|
66
|
+
if (!response.ok) {
|
|
67
|
+
const data2 = await response.json().catch(() => ({}));
|
|
68
|
+
throw new Error(data2.error || "Failed to subscribe");
|
|
69
|
+
}
|
|
70
|
+
const data = await response.json();
|
|
71
|
+
setIsSuccess(true);
|
|
72
|
+
setIsLoading(false);
|
|
73
|
+
return {
|
|
74
|
+
success: true,
|
|
75
|
+
subscriberId: data.subscriber?.id,
|
|
76
|
+
message: data.message
|
|
77
|
+
};
|
|
78
|
+
} catch (err) {
|
|
79
|
+
const error2 = err instanceof Error ? err : new Error("Unknown error");
|
|
80
|
+
setError(error2);
|
|
81
|
+
setIsLoading(false);
|
|
82
|
+
return { success: false, message: error2.message };
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
[baseUrl, publicKey]
|
|
86
|
+
);
|
|
87
|
+
return {
|
|
88
|
+
subscribe,
|
|
89
|
+
isLoading,
|
|
90
|
+
error,
|
|
91
|
+
isSuccess,
|
|
92
|
+
reset
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function SubscribeForm({
|
|
96
|
+
tags,
|
|
97
|
+
onSuccess,
|
|
98
|
+
onError,
|
|
99
|
+
className,
|
|
100
|
+
placeholder = "Enter your email",
|
|
101
|
+
buttonText = "Subscribe",
|
|
102
|
+
loadingText = "Subscribing...",
|
|
103
|
+
successMessage = "Thanks for subscribing!",
|
|
104
|
+
showNameFields = false,
|
|
105
|
+
style
|
|
106
|
+
}) {
|
|
107
|
+
const { subscribe, isLoading, error, isSuccess, reset } = useSubscribe();
|
|
108
|
+
const [email, setEmail] = react.useState("");
|
|
109
|
+
const [firstName, setFirstName] = react.useState("");
|
|
110
|
+
const [lastName, setLastName] = react.useState("");
|
|
111
|
+
const handleSubmit = async (e) => {
|
|
112
|
+
e.preventDefault();
|
|
113
|
+
const result = await subscribe({
|
|
114
|
+
email,
|
|
115
|
+
firstName: showNameFields ? firstName : void 0,
|
|
116
|
+
lastName: showNameFields ? lastName : void 0,
|
|
117
|
+
tags
|
|
118
|
+
});
|
|
119
|
+
if (result.success) {
|
|
120
|
+
onSuccess?.();
|
|
121
|
+
setEmail("");
|
|
122
|
+
setFirstName("");
|
|
123
|
+
setLastName("");
|
|
124
|
+
} else if (error) {
|
|
125
|
+
onError?.(error);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
if (isSuccess) {
|
|
129
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style, children: [
|
|
130
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "#10b981", margin: 0 }, children: successMessage }),
|
|
131
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
132
|
+
"button",
|
|
133
|
+
{
|
|
134
|
+
type: "button",
|
|
135
|
+
onClick: reset,
|
|
136
|
+
style: {
|
|
137
|
+
marginTop: "8px",
|
|
138
|
+
padding: "4px 8px",
|
|
139
|
+
fontSize: "12px",
|
|
140
|
+
background: "transparent",
|
|
141
|
+
border: "1px solid #ccc",
|
|
142
|
+
borderRadius: "4px",
|
|
143
|
+
cursor: "pointer"
|
|
144
|
+
},
|
|
145
|
+
children: "Subscribe another"
|
|
146
|
+
}
|
|
147
|
+
)
|
|
148
|
+
] });
|
|
149
|
+
}
|
|
150
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className, style, children: [
|
|
151
|
+
showNameFields && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "8px", marginBottom: "8px" }, children: [
|
|
152
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
153
|
+
"input",
|
|
154
|
+
{
|
|
155
|
+
type: "text",
|
|
156
|
+
value: firstName,
|
|
157
|
+
onChange: (e) => setFirstName(e.target.value),
|
|
158
|
+
placeholder: "First name",
|
|
159
|
+
style: {
|
|
160
|
+
flex: 1,
|
|
161
|
+
padding: "8px 12px",
|
|
162
|
+
border: "1px solid #ccc",
|
|
163
|
+
borderRadius: "4px"
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
),
|
|
167
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
168
|
+
"input",
|
|
169
|
+
{
|
|
170
|
+
type: "text",
|
|
171
|
+
value: lastName,
|
|
172
|
+
onChange: (e) => setLastName(e.target.value),
|
|
173
|
+
placeholder: "Last name",
|
|
174
|
+
style: {
|
|
175
|
+
flex: 1,
|
|
176
|
+
padding: "8px 12px",
|
|
177
|
+
border: "1px solid #ccc",
|
|
178
|
+
borderRadius: "4px"
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
)
|
|
182
|
+
] }),
|
|
183
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "8px" }, children: [
|
|
184
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
185
|
+
"input",
|
|
186
|
+
{
|
|
187
|
+
type: "email",
|
|
188
|
+
value: email,
|
|
189
|
+
onChange: (e) => setEmail(e.target.value),
|
|
190
|
+
placeholder,
|
|
191
|
+
required: true,
|
|
192
|
+
disabled: isLoading,
|
|
193
|
+
style: {
|
|
194
|
+
flex: 1,
|
|
195
|
+
padding: "8px 12px",
|
|
196
|
+
border: "1px solid #ccc",
|
|
197
|
+
borderRadius: "4px"
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
),
|
|
201
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
202
|
+
"button",
|
|
203
|
+
{
|
|
204
|
+
type: "submit",
|
|
205
|
+
disabled: isLoading || !email,
|
|
206
|
+
style: {
|
|
207
|
+
padding: "8px 16px",
|
|
208
|
+
backgroundColor: isLoading ? "#9ca3af" : "#3b82f6",
|
|
209
|
+
color: "white",
|
|
210
|
+
border: "none",
|
|
211
|
+
borderRadius: "4px",
|
|
212
|
+
cursor: isLoading ? "not-allowed" : "pointer",
|
|
213
|
+
fontWeight: 500
|
|
214
|
+
},
|
|
215
|
+
children: isLoading ? loadingText : buttonText
|
|
216
|
+
}
|
|
217
|
+
)
|
|
218
|
+
] }),
|
|
219
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "#ef4444", fontSize: "14px", marginTop: "8px" }, children: error.message })
|
|
220
|
+
] });
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
exports.SendMailOSProvider = SendMailOSProvider;
|
|
224
|
+
exports.SubscribeForm = SubscribeForm;
|
|
225
|
+
exports.useSendMailOS = useSendMailOS;
|
|
226
|
+
exports.useSubscribe = useSubscribe;
|
|
227
|
+
//# sourceMappingURL=index.js.map
|
|
228
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/react/provider.tsx","../../src/react/use-subscribe.ts","../../src/react/subscribe-form.tsx"],"names":["createContext","useMemo","jsx","useContext","useState","useCallback","data","error","jsxs"],"mappings":"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","file":"index.js","sourcesContent":["import React, { createContext, useContext, useMemo } from 'react';\n\ninterface SendMailOSContextValue {\n publicKey: string;\n baseUrl: string;\n}\n\nconst SendMailOSContext = createContext<SendMailOSContextValue | null>(null);\n\nexport interface SendMailOSProviderProps {\n /** Your public key (pk_live_... or pk_test_...) */\n publicKey: string;\n /** Custom API base URL (optional) */\n baseUrl?: string;\n children: React.ReactNode;\n}\n\n/**\n * Provider component for SendMailOS React integration\n * \n * @example\n * ```tsx\n * import { SendMailOSProvider } from '@sendmailos/sdk/react';\n * \n * function App() {\n * return (\n * <SendMailOSProvider publicKey=\"pk_live_...\">\n * <YourApp />\n * </SendMailOSProvider>\n * );\n * }\n * ```\n */\nexport function SendMailOSProvider({\n publicKey,\n baseUrl = 'https://api.sendmailos.com/api/v1',\n children,\n}: SendMailOSProviderProps) {\n if (!publicKey) {\n throw new Error('SendMailOSProvider requires a publicKey');\n }\n\n if (!publicKey.startsWith('pk_')) {\n console.warn(\n '[SendMailOS] Public keys should start with \"pk_\". ' +\n 'Never expose secret keys (sk_) in client-side code.'\n );\n }\n\n const value = useMemo(\n () => ({\n publicKey,\n baseUrl: baseUrl.replace(/\\/$/, ''),\n }),\n [publicKey, baseUrl]\n );\n\n return (\n <SendMailOSContext.Provider value={value}>\n {children}\n </SendMailOSContext.Provider>\n );\n}\n\n/**\n * Hook to access SendMailOS context\n */\nexport function useSendMailOS(): SendMailOSContextValue {\n const context = useContext(SendMailOSContext);\n \n if (!context) {\n throw new Error('useSendMailOS must be used within a SendMailOSProvider');\n }\n \n return context;\n}\n","import { useState, useCallback } from 'react';\nimport { useSendMailOS } from './provider';\n\ninterface SubscribeParams {\n email: string;\n firstName?: string;\n lastName?: string;\n tags?: string[];\n}\n\ninterface SubscribeResult {\n success: boolean;\n subscriberId?: string;\n message?: string;\n}\n\ninterface UseSubscribeReturn {\n /** Subscribe a new email address */\n subscribe: (params: SubscribeParams) => Promise<SubscribeResult>;\n /** Loading state */\n isLoading: boolean;\n /** Error message if subscription failed */\n error: Error | null;\n /** Success state */\n isSuccess: boolean;\n /** Reset the hook state */\n reset: () => void;\n}\n\n/**\n * Hook for subscribing users to your email list\n * \n * @example\n * ```tsx\n * function NewsletterForm() {\n * const { subscribe, isLoading, error, isSuccess } = useSubscribe();\n * const [email, setEmail] = useState('');\n * \n * const handleSubmit = async (e) => {\n * e.preventDefault();\n * await subscribe({ email, tags: ['newsletter'] });\n * };\n * \n * if (isSuccess) {\n * return <p>Thanks for subscribing!</p>;\n * }\n * \n * return (\n * <form onSubmit={handleSubmit}>\n * <input\n * type=\"email\"\n * value={email}\n * onChange={(e) => setEmail(e.target.value)}\n * placeholder=\"Enter your email\"\n * />\n * <button disabled={isLoading}>\n * {isLoading ? 'Subscribing...' : 'Subscribe'}\n * </button>\n * {error && <p>{error.message}</p>}\n * </form>\n * );\n * }\n * ```\n */\nexport function useSubscribe(): UseSubscribeReturn {\n const { publicKey, baseUrl } = useSendMailOS();\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [isSuccess, setIsSuccess] = useState(false);\n\n const reset = useCallback(() => {\n setIsLoading(false);\n setError(null);\n setIsSuccess(false);\n }, []);\n\n const subscribe = useCallback(\n async (params: SubscribeParams): Promise<SubscribeResult> => {\n setIsLoading(true);\n setError(null);\n setIsSuccess(false);\n\n try {\n const response = await fetch(`${baseUrl}/public/subscribe`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Public-Key': publicKey,\n },\n body: JSON.stringify({\n email: params.email,\n first_name: params.firstName,\n last_name: params.lastName,\n tags: params.tags,\n }),\n });\n\n if (!response.ok) {\n const data = await response.json().catch(() => ({}));\n throw new Error(data.error || 'Failed to subscribe');\n }\n\n const data = await response.json();\n setIsSuccess(true);\n setIsLoading(false);\n\n return {\n success: true,\n subscriberId: data.subscriber?.id,\n message: data.message,\n };\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Unknown error');\n setError(error);\n setIsLoading(false);\n return { success: false, message: error.message };\n }\n },\n [baseUrl, publicKey]\n );\n\n return {\n subscribe,\n isLoading,\n error,\n isSuccess,\n reset,\n };\n}\n","import React, { useState, FormEvent } from 'react';\nimport { useSubscribe } from './use-subscribe';\n\nexport interface SubscribeFormProps {\n /** Tags to apply to new subscribers */\n tags?: string[];\n /** Callback when subscription succeeds */\n onSuccess?: () => void;\n /** Callback when subscription fails */\n onError?: (error: Error) => void;\n /** CSS class for the form container */\n className?: string;\n /** Placeholder text for email input */\n placeholder?: string;\n /** Text for submit button */\n buttonText?: string;\n /** Text shown while loading */\n loadingText?: string;\n /** Text shown on success */\n successMessage?: string;\n /** Whether to show first/last name fields */\n showNameFields?: boolean;\n /** Custom styles */\n style?: React.CSSProperties;\n}\n\n/**\n * Pre-built newsletter subscription form\n * \n * @example\n * ```tsx\n * import { SubscribeForm } from '@sendmailos/sdk/react';\n * \n * function Newsletter() {\n * return (\n * <SubscribeForm\n * tags={['newsletter']}\n * onSuccess={() => console.log('Subscribed!')}\n * buttonText=\"Join Newsletter\"\n * placeholder=\"you@example.com\"\n * />\n * );\n * }\n * ```\n */\nexport function SubscribeForm({\n tags,\n onSuccess,\n onError,\n className,\n placeholder = 'Enter your email',\n buttonText = 'Subscribe',\n loadingText = 'Subscribing...',\n successMessage = 'Thanks for subscribing!',\n showNameFields = false,\n style,\n}: SubscribeFormProps) {\n const { subscribe, isLoading, error, isSuccess, reset } = useSubscribe();\n const [email, setEmail] = useState('');\n const [firstName, setFirstName] = useState('');\n const [lastName, setLastName] = useState('');\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault();\n \n const result = await subscribe({\n email,\n firstName: showNameFields ? firstName : undefined,\n lastName: showNameFields ? lastName : undefined,\n tags,\n });\n\n if (result.success) {\n onSuccess?.();\n setEmail('');\n setFirstName('');\n setLastName('');\n } else if (error) {\n onError?.(error);\n }\n };\n\n if (isSuccess) {\n return (\n <div className={className} style={style}>\n <p style={{ color: '#10b981', margin: 0 }}>{successMessage}</p>\n <button\n type=\"button\"\n onClick={reset}\n style={{\n marginTop: '8px',\n padding: '4px 8px',\n fontSize: '12px',\n background: 'transparent',\n border: '1px solid #ccc',\n borderRadius: '4px',\n cursor: 'pointer',\n }}\n >\n Subscribe another\n </button>\n </div>\n );\n }\n\n return (\n <form onSubmit={handleSubmit} className={className} style={style}>\n {showNameFields && (\n <div style={{ display: 'flex', gap: '8px', marginBottom: '8px' }}>\n <input\n type=\"text\"\n value={firstName}\n onChange={(e) => setFirstName(e.target.value)}\n placeholder=\"First name\"\n style={{\n flex: 1,\n padding: '8px 12px',\n border: '1px solid #ccc',\n borderRadius: '4px',\n }}\n />\n <input\n type=\"text\"\n value={lastName}\n onChange={(e) => setLastName(e.target.value)}\n placeholder=\"Last name\"\n style={{\n flex: 1,\n padding: '8px 12px',\n border: '1px solid #ccc',\n borderRadius: '4px',\n }}\n />\n </div>\n )}\n \n <div style={{ display: 'flex', gap: '8px' }}>\n <input\n type=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder={placeholder}\n required\n disabled={isLoading}\n style={{\n flex: 1,\n padding: '8px 12px',\n border: '1px solid #ccc',\n borderRadius: '4px',\n }}\n />\n <button\n type=\"submit\"\n disabled={isLoading || !email}\n style={{\n padding: '8px 16px',\n backgroundColor: isLoading ? '#9ca3af' : '#3b82f6',\n color: 'white',\n border: 'none',\n borderRadius: '4px',\n cursor: isLoading ? 'not-allowed' : 'pointer',\n fontWeight: 500,\n }}\n >\n {isLoading ? loadingText : buttonText}\n </button>\n </div>\n \n {error && (\n <p style={{ color: '#ef4444', fontSize: '14px', marginTop: '8px' }}>\n {error.message}\n </p>\n )}\n </form>\n );\n}\n"]}
|