Skip to content

Commit a577208

Browse files
committed
improve code a bit more
1 parent d47ab37 commit a577208

File tree

5 files changed

+77
-83
lines changed

5 files changed

+77
-83
lines changed

packages/preview-server/src/actions/has-resend-api-key.ts

Lines changed: 0 additions & 7 deletions
This file was deleted.

packages/preview-server/src/app/preview/[...slug]/page.tsx

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,15 @@ import { Toolbar } from '../../../components/toolbar';
1212
import type { LintingRow } from '../../../components/toolbar/linter';
1313
import type { SpamCheckingResult } from '../../../components/toolbar/spam-assassin';
1414
import { PreviewProvider } from '../../../contexts/preview';
15+
import { ToolbarProvider } from '../../../contexts/toolbar';
1516
import { getEmailsDirectoryMetadata } from '../../../utils/get-emails-directory-metadata';
1617
import { getLintingSources, loadLintingRowsFrom } from '../../../utils/linting';
1718
import { loadStream } from '../../../utils/load-stream';
18-
import { emailsDirectoryAbsolutePath, isBuilding } from '../../env';
19+
import {
20+
emailsDirectoryAbsolutePath,
21+
isBuilding,
22+
resendApiKey,
23+
} from '../../env';
1924
import Preview from './preview';
2025

2126
export const dynamicParams = true;
@@ -132,11 +137,13 @@ This is most likely not an issue with the preview server. Maybe there was a typo
132137
<Suspense>
133138
<Preview emailTitle={path.basename(emailPath)} />
134139

135-
<Toolbar
136-
serverLintingRows={lintingRows}
137-
serverSpamCheckingResult={spamCheckingResult}
138-
serverCompatibilityResults={compatibilityCheckingResults}
139-
/>
140+
<ToolbarProvider hasApiKey={(resendApiKey ?? '').trim().length > 0}>
141+
<Toolbar
142+
serverLintingRows={lintingRows}
143+
serverSpamCheckingResult={spamCheckingResult}
144+
serverCompatibilityResults={compatibilityCheckingResults}
145+
/>
146+
</ToolbarProvider>
140147
</Suspense>
141148
</Shell>
142149
</PreviewProvider>

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

Lines changed: 16 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as React from 'react';
77
import type { CompatibilityCheckingResult } from '../actions/email-validation/check-compatibility';
88
import { isBuilding } from '../app/env';
99
import { usePreviewContext } from '../contexts/preview';
10+
import { useToolbarContext } from '../contexts/toolbar';
1011
import { cn } from '../utils';
1112
import CodeSnippet from './code-snippet';
1213
import { IconArrowDown } from './icons/icon-arrow-down';
@@ -15,7 +16,7 @@ import { IconInfo } from './icons/icon-info';
1516
import { IconReload } from './icons/icon-reload';
1617
import { Compatibility, useCompatibility } from './toolbar/compatibility';
1718
import { Linter, type LintingRow, useLinter } from './toolbar/linter';
18-
import { Resend, useResend } from './toolbar/resend';
19+
import { ResendIntegration } from './toolbar/resend';
1920
import {
2021
SpamAssassin,
2122
type SpamCheckingResult,
@@ -65,6 +66,8 @@ const ToolbarInner = ({
6566
const searchParams = useSearchParams();
6667
const router = useRouter();
6768

69+
const { hasSetupResendIntegration } = useToolbarContext();
70+
6871
const { activeTab, toggled } = useToolbarState();
6972

7073
const setActivePanelValue = (newValue: ToolbarTabValue | undefined) => {
@@ -111,9 +114,6 @@ const ToolbarInner = ({
111114
initialResults: serverCompatibilityResults ?? cachedCompatibilityResults,
112115
});
113116

114-
const [resendStatus, { load: loadResend, loading: resendLoading }] =
115-
useResend();
116-
117117
if (!isBuilding) {
118118
// biome-ignore lint/correctness/useHookAtTopLevel: This is fine since isBuilding does not change at runtime
119119
React.useEffect(() => {
@@ -126,8 +126,6 @@ const ToolbarInner = ({
126126

127127
const compatibilityCheckingResults = await loadCompatibility();
128128
setCachedCompatibilityResults(compatibilityCheckingResults);
129-
130-
await loadResend();
131129
})();
132130
}, []);
133131
}
@@ -191,15 +189,10 @@ const ToolbarInner = ({
191189
>
192190
<IconInfo size={24} />
193191
</ToolbarButton>
194-
{isBuilding ? null : (
192+
{isBuilding || activeTab === 'resend' ? null : (
195193
<ToolbarButton
196194
tooltip="Reload"
197-
disabled={
198-
lintLoading ||
199-
spamLoading ||
200-
compatibilityLoading ||
201-
resendLoading
202-
}
195+
disabled={lintLoading || spamLoading || compatibilityLoading}
203196
onClick={async () => {
204197
if (activeTab === undefined) {
205198
setActivePanelValue('linter');
@@ -210,19 +203,14 @@ const ToolbarInner = ({
210203
await loadLinting();
211204
} else if (activeTab === 'compatibility') {
212205
await loadCompatibility();
213-
} else if (activeTab === 'resend') {
214-
await loadResend();
215206
}
216207
}}
217208
>
218209
<IconReload
219210
size={24}
220211
className={cn({
221212
'opacity-60 animate-spin-fast':
222-
lintLoading ||
223-
spamLoading ||
224-
compatibilityLoading ||
225-
resendLoading,
213+
lintLoading || spamLoading || compatibilityLoading,
226214
})}
227215
/>
228216
</ToolbarButton>
@@ -292,16 +280,17 @@ const ToolbarInner = ({
292280
)}
293281
</Tabs.Content>
294282
<Tabs.Content value="resend">
295-
{resendLoading ? (
296-
<LoadingState message="Checking Resend API Key..." />
297-
) : resendStatus?.hasApiKey ? (
298-
<Resend emailSlug={emailSlug} htmlMarkup={prettyMarkup} />
283+
{hasSetupResendIntegration ? (
284+
<ResendIntegration
285+
emailSlug={emailSlug}
286+
htmlMarkup={prettyMarkup}
287+
/>
299288
) : (
300289
<SuccessWrapper>
301290
<SuccessTitle>Connect to Resend</SuccessTitle>
302291
<SuccessDescription>
303292
Run <CodeSnippet>email resend setup re_xxxxxx</CodeSnippet>{' '}
304-
to connect your Resend account.
293+
to connect your Resend account and refresh.
305294
</SuccessDescription>
306295
</SuccessWrapper>
307296
)}
@@ -371,11 +360,11 @@ interface ToolbarProps {
371360
serverCompatibilityResults: CompatibilityCheckingResult[] | undefined;
372361
}
373362

374-
export const Toolbar = ({
363+
export function Toolbar({
375364
serverLintingRows,
376365
serverSpamCheckingResult,
377366
serverCompatibilityResults,
378-
}: ToolbarProps) => {
367+
}: ToolbarProps) {
379368
const { emailPath, emailSlug, renderedEmailMetadata } = usePreviewContext();
380369

381370
if (renderedEmailMetadata === undefined) return null;
@@ -393,4 +382,4 @@ export const Toolbar = ({
393382
serverCompatibilityResults={serverCompatibilityResults}
394383
/>
395384
);
396-
};
385+
}

packages/preview-server/src/components/toolbar/resend.tsx

Lines changed: 13 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { useAction } from 'next-safe-action/hooks';
2-
import { useRef, useState } from 'react';
2+
import { useState } from 'react';
33
import { exportSingleTemplate } from '../../actions/export-single-template';
44
import { getEmailPathFromSlug } from '../../actions/get-email-path-from-slug';
5-
import { hasResendApiKey } from '../../actions/has-resend-api-key';
65
import { renderEmailByPath } from '../../actions/render-email-by-path';
76
import { useEmails } from '../../contexts/emails';
87
import type { EmailsDirectory } from '../../utils/get-emails-directory-metadata';
@@ -18,50 +17,21 @@ export interface ResendStatus {
1817
error: string | null;
1918
}
2019

21-
export const useResend = ({
22-
initialStatus,
23-
}: {
24-
initialStatus?: ResendStatus;
25-
} = {}) => {
26-
const [status, setStatus] = useState<ResendStatus | undefined>(initialStatus);
27-
const [loading, setLoading] = useState(false);
28-
const isLoadingRef = useRef(false);
29-
30-
const load = async () => {
31-
if (isLoadingRef.current) return;
32-
isLoadingRef.current = true;
33-
setLoading(true);
34-
35-
try {
36-
if (await hasResendApiKey()) {
37-
const result = { hasApiKey: true, error: null };
38-
setStatus(result);
39-
return result;
40-
}
41-
} catch (exception) {
42-
console.error('Error checking Resend API key', exception);
43-
} finally {
44-
setLoading(false);
45-
isLoadingRef.current = false;
46-
}
47-
};
48-
49-
return [status, { loading, load }] as const;
50-
};
51-
5220
interface ResendItem {
5321
status: 'uploading' | 'failed' | 'succeeded';
5422
name: string;
5523
id?: string;
5624
}
5725

58-
export const Resend = ({
59-
emailSlug,
60-
htmlMarkup,
61-
}: {
26+
type ResendIntegrationProps = {
6227
emailSlug: string;
6328
htmlMarkup: string;
64-
}) => {
29+
};
30+
31+
export function ResendIntegration({
32+
emailSlug,
33+
htmlMarkup,
34+
}: ResendIntegrationProps) {
6535
const { emailsDirectoryMetadata } = useEmails();
6636
const [items, setItems] = useState<ResendItem[]>([]);
6737
const [isBulkProcessing, setIsBulkProcessing] = useState(false);
@@ -163,10 +133,10 @@ export const Resend = ({
163133
prevItems.map((item, index) =>
164134
index === i
165135
? {
166-
...item,
167-
status: 'succeeded',
168-
id: exportResult.data!.id,
169-
}
136+
...item,
137+
status: 'succeeded',
138+
id: exportResult.data!.id,
139+
}
170140
: item,
171141
),
172142
);
@@ -250,7 +220,7 @@ export const Resend = ({
250220
))}
251221
</Results>
252222
);
253-
};
223+
}
254224

255225
const SuccessWrapper = ({ children }: { children: React.ReactNode }) => {
256226
return (
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
'use client';
2+
3+
import { createContext, use } from 'react';
4+
5+
const ToolbarContext = createContext<
6+
| {
7+
hasSetupResendIntegration: boolean;
8+
}
9+
| undefined
10+
>(undefined);
11+
12+
interface ToolbarProviderProps {
13+
hasApiKey: boolean;
14+
children: React.ReactNode;
15+
}
16+
17+
export function ToolbarProvider({ hasApiKey, children }: ToolbarProviderProps) {
18+
return (
19+
<ToolbarContext.Provider value={{ hasSetupResendIntegration: hasApiKey }}>
20+
{children}
21+
</ToolbarContext.Provider>
22+
);
23+
}
24+
25+
export const useToolbarContext = () => {
26+
const previewContext = use(ToolbarContext);
27+
28+
if (typeof previewContext === 'undefined') {
29+
throw new Error(
30+
'Cannot call `useToolbarContext` outside of a `ToolbarContext` provider.',
31+
);
32+
}
33+
34+
return previewContext;
35+
};

0 commit comments

Comments
 (0)