Skip to content

Commit 353784c

Browse files
committed
separate into a server action, because the fetch throws an exception in the brwoser
1 parent e632bb0 commit 353784c

File tree

2 files changed

+42
-74
lines changed

2 files changed

+42
-74
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
'use server';
2+
3+
export async function sendTestEmail(
4+
to: string,
5+
subject: string,
6+
html: string,
7+
): Promise<{ ok: boolean; status: number }> {
8+
const response = await fetch('https://react.email/api/send/test', {
9+
method: 'POST',
10+
headers: { 'Content-Type': 'application/json' },
11+
body: JSON.stringify({
12+
to,
13+
subject,
14+
html,
15+
}),
16+
});
17+
18+
return { ok: response.ok, status: response.status };
19+
}

packages/preview-server/src/components/send.tsx

Lines changed: 23 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,30 @@
11
import * as Popover from '@radix-ui/react-popover';
2-
import { useId, useRef, useState } from 'react';
2+
import { useId, useState } from 'react';
33
import { toast } from 'sonner';
4+
import { sendTestEmail } from '../actions/send-test-email';
45
import { Button } from './button';
56
import { Text } from './text';
67

7-
const useTimer = (startingSeconds: number, onStop?: () => void) => {
8-
const [isActive, setIsActive] = useState(false);
9-
const [secondsRemaining, setSecondsRemaining] = useState(startingSeconds);
10-
11-
const interval = useRef<NodeJS.Timeout | undefined>(undefined);
12-
13-
return {
14-
isActive,
15-
secondsRemaining,
16-
start: () => {
17-
setIsActive(true);
18-
setSecondsRemaining(startingSeconds);
19-
clearInterval(interval.current);
20-
21-
let secondsRemainingTemp = startingSeconds;
22-
interval.current = setInterval(() => {
23-
setSecondsRemaining((v) => v - 1);
24-
secondsRemainingTemp -= 1;
25-
26-
if (secondsRemainingTemp <= 0) {
27-
clearInterval(interval.current);
28-
setIsActive(false);
29-
setSecondsRemaining(startingSeconds);
30-
onStop?.();
31-
}
32-
}, 1_000);
33-
},
34-
};
35-
};
36-
378
export const Send = ({ markup }: { markup: string }) => {
389
const [to, setTo] = useState('');
3910
const [subject, setSubject] = useState('Testing React Email');
4011
const [isSending, setIsSending] = useState(false);
4112
const [isPopOverOpen, setIsPopOverOpen] = useState(false);
4213

43-
const [isRateLimited, setIsRateLimited] = useState(false);
44-
const rateLimiter = useTimer(60, () => {
45-
setIsRateLimited(false);
46-
});
47-
4814
const onFormSubmit = async (e: React.FormEvent) => {
4915
e.preventDefault();
5016
setIsSending(true);
5117

52-
try {
53-
const response = await fetch('https://react.email/api/send/test', {
54-
method: 'POST',
55-
headers: { 'Content-Type': 'application/json' },
56-
body: JSON.stringify({
57-
to,
58-
subject,
59-
html: markup,
60-
}),
61-
});
18+
const response = await sendTestEmail(to, subject, markup);
6219

63-
if (!rateLimiter.isActive) {
64-
rateLimiter.start();
65-
}
66-
67-
if (response.ok) {
68-
toast.success('Email sent! Check your inbox.');
69-
} else if (response.status === 429) {
70-
toast.error('Too many requests.');
71-
rateLimiter.start();
72-
setIsRateLimited(true);
73-
} else {
74-
toast.error('Something went wrong. Please try again.');
75-
}
76-
} catch {
20+
if (response.ok) {
21+
toast.success('Email sent! Check your inbox.');
22+
} else if (response.status === 429) {
23+
toast.error('Too many requests. Try again in around 1 minute');
24+
} else {
7725
toast.error('Something went wrong. Please try again.');
7826
}
27+
7928
setIsSending(false);
8029
};
8130

@@ -151,29 +100,29 @@ export const Send = ({ markup }: { markup: string }) => {
151100
type="checkbox"
152101
/>
153102
<div className="mt-3 flex items-center justify-between">
154-
<Text className="inline-block" size="1">
155-
Powered by{' '}
156-
<a
157-
className="text-white/85 transition duration-300 ease-in-out hover:text-slate-12"
158-
href="https://go.resend.com/react-email"
159-
rel="noreferrer"
160-
target="_blank"
161-
>
162-
Resend
163-
</a>
164-
</Text>
103+
<div className="flex flex-col inline-block">
104+
<Text size="1">
105+
Powered by{' '}
106+
<a
107+
className="text-white/85 transition duration-300 ease-in-out hover:text-slate-12"
108+
href="https://go.resend.com/react-email"
109+
rel="noreferrer"
110+
target="_blank"
111+
>
112+
Resend
113+
</a>
114+
</Text>
115+
</div>
165116
<Button
166117
className="disabled:border-transparent disabled:bg-slate-11"
167118
disabled={
168119
subject.length === 0 ||
169120
to.length === 0 ||
170-
isSending ||
171-
isRateLimited
121+
isSending
172122
}
173123
type="submit"
174124
>
175125
Send
176-
{isRateLimited ? ` ${rateLimiter.secondsRemaining}s` : null}
177126
</Button>
178127
</div>
179128
</form>

0 commit comments

Comments
 (0)