Skip to content

Commit 0a73d53

Browse files
committed
fix(dashboard): show public website link immediately
1 parent e6a9c5b commit 0a73d53

1 file changed

Lines changed: 67 additions & 9 deletions

File tree

  • apps/dashboard/app/(main)/websites/[id]/settings/general

apps/dashboard/app/(main)/websites/[id]/settings/general/page.tsx

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,21 @@ import { toast } from "sonner";
77
import { NoticeBanner } from "@/app/(main)/websites/_components/notice-banner";
88
import { useCopyToClipboard } from "@/hooks/use-copy-to-clipboard";
99
import {
10+
getWebsiteByIdKey,
11+
getWebsitesListKey,
1012
updateWebsiteCache,
1113
useDeleteWebsite,
1214
useUpdateWebsite,
1315
useWebsite,
1416
type Website,
17+
type WebsitesListData,
1518
} from "@/hooks/use-websites";
1619
import { orpc } from "@/lib/orpc";
20+
import { publicConfig } from "@databuddy/env/public";
1721
import { TOAST_MESSAGES } from "../../_components/constants/settings-constants";
1822
import {
1923
ArrowRightIcon,
24+
ArrowSquareOutIcon,
2025
CheckIcon,
2126
ClipboardIcon,
2227
GlobeIcon,
@@ -71,6 +76,45 @@ export default function GeneralSettingsPage() {
7176

7277
const toggleMutation = useMutation({
7378
...orpc.websites.togglePublic.mutationOptions(),
79+
onMutate: async ({ id, isPublic: nextIsPublic }) => {
80+
const getByIdKey = getWebsiteByIdKey(id);
81+
const listKey = getWebsitesListKey();
82+
83+
await Promise.all([
84+
queryClient.cancelQueries({ queryKey: getByIdKey }),
85+
queryClient.cancelQueries({ queryKey: listKey }),
86+
]);
87+
88+
const previousWebsite = queryClient.getQueryData<Website>(getByIdKey);
89+
const previousList = queryClient.getQueryData<WebsitesListData>(listKey);
90+
const withPublicState = (website: Website): Website => ({
91+
...website,
92+
isPublic: nextIsPublic,
93+
});
94+
95+
queryClient.setQueryData<Website>(getByIdKey, (current) =>
96+
current ? withPublicState(current) : current
97+
);
98+
queryClient.setQueryData<WebsitesListData>(listKey, (current) =>
99+
current
100+
? {
101+
...current,
102+
websites: current.websites.map((website) =>
103+
website.id === id ? withPublicState(website) : website
104+
),
105+
}
106+
: current
107+
);
108+
109+
return { getByIdKey, listKey, previousList, previousWebsite };
110+
},
111+
onError: (_error, _variables, context) => {
112+
if (!context) {
113+
return;
114+
}
115+
queryClient.setQueryData(context.getByIdKey, context.previousWebsite);
116+
queryClient.setQueryData(context.listKey, context.previousList);
117+
},
74118
onSuccess: (updatedWebsite: Website) => {
75119
updateWebsiteCache(queryClient, updatedWebsite);
76120
queryClient.invalidateQueries({
@@ -95,13 +139,14 @@ export default function GeneralSettingsPage() {
95139
onCopy: () => toast.success("Public link copied to clipboard"),
96140
});
97141

98-
const isPublic = websiteData?.isPublic ?? false;
99-
const shareableLink = useMemo(() => {
100-
if (!(websiteData && typeof window !== "undefined")) {
101-
return "";
102-
}
103-
return `${window.location.origin}/public/${websiteId}`;
104-
}, [websiteData, websiteId]);
142+
const isPublic =
143+
(toggleMutation.isPending
144+
? toggleMutation.variables?.isPublic
145+
: websiteData?.isPublic) ?? false;
146+
const shareableLink = useMemo(
147+
() => `${publicConfig.urls.dashboard}/public/${websiteId}`,
148+
[websiteId]
149+
);
105150

106151
const hasChanges =
107152
!!websiteData &&
@@ -173,6 +218,10 @@ export default function GeneralSettingsPage() {
173218
[websiteData, websiteId, toggleMutation]
174219
);
175220

221+
const handleOpenPublicPage = useCallback(() => {
222+
window.open(shareableLink, "_blank", "noopener,noreferrer");
223+
}, [shareableLink]);
224+
176225
if (!websiteData) {
177226
return <GeneralSettingsSkeleton />;
178227
}
@@ -271,11 +320,11 @@ export default function GeneralSettingsPage() {
271320
</div>
272321
<div className="flex items-center gap-2">
273322
<code className="min-w-0 flex-1 overflow-x-auto break-all rounded border bg-secondary px-3 py-2 font-mono text-xs">
274-
{shareableLink || `/public/${websiteId}`}
323+
{shareableLink}
275324
</code>
276325
<Button
277326
aria-label="Copy public overview link"
278-
disabled={!(isPublic && shareableLink)}
327+
disabled={!isPublic}
279328
onClick={() => copyLink(shareableLink)}
280329
size="sm"
281330
variant="ghost"
@@ -286,6 +335,15 @@ export default function GeneralSettingsPage() {
286335
<ClipboardIcon className="size-4" />
287336
)}
288337
</Button>
338+
<Button
339+
aria-label="Open public overview"
340+
disabled={!isPublic}
341+
onClick={handleOpenPublicPage}
342+
size="sm"
343+
variant="ghost"
344+
>
345+
<ArrowSquareOutIcon className="size-4" />
346+
</Button>
289347
</div>
290348
<NoticeBanner
291349
description={

0 commit comments

Comments
 (0)