Skip to content

Commit e932b44

Browse files
committed
Enhance error handling in CommentsSection and update CSP for Firebase functions. Add staff profile handling in public authentication context.
1 parent 20352c1 commit e932b44

3 files changed

Lines changed: 52 additions & 7 deletions

File tree

components/CommentsSection.tsx

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,16 @@ function sortRepliesWithPriority(
183183
return [...staffReplies, ...regularReplies];
184184
}
185185

186+
function callableErrorMessage(error: unknown, fallback: string) {
187+
if (typeof error === "object" && error && "message" in error) {
188+
const message = String((error as { message: string }).message)
189+
.replace(/^FirebaseError:\s*/i, "")
190+
.trim();
191+
if (message && !/^(internal|internal error)$/i.test(message)) return message;
192+
}
193+
return fallback;
194+
}
195+
186196
function ReaderAvatar({
187197
name,
188198
photoURL,
@@ -1282,7 +1292,7 @@ export default function CommentsSection({
12821292
} catch (submitError) {
12831293
await deleteMultipleCommentImagesSafe(storage, uploadedImages);
12841294
console.error("Unable to post comment:", submitError);
1285-
setError("We could not post your comment. Please try again.");
1295+
setError(callableErrorMessage(submitError, "We could not post your comment. Please try again."));
12861296
} finally {
12871297
setBusyId(null);
12881298
}
@@ -1341,7 +1351,7 @@ export default function CommentsSection({
13411351
} catch (replyError) {
13421352
await deleteMultipleCommentImagesSafe(storage, uploadedImages);
13431353
console.error("Unable to post reply:", replyError);
1344-
setError("We could not post your reply. Please try again.");
1354+
setError(callableErrorMessage(replyError, "We could not post your reply. Please try again."));
13451355
} finally {
13461356
setReplyBusyId(null);
13471357
}
@@ -1740,13 +1750,15 @@ export default function CommentsSection({
17401750
) : !authLoading && user && !profile?.handle ? (
17411751
<div className="flex flex-wrap items-center justify-between gap-4 border-b border-white/30 py-7">
17421752
<p className="font-light text-white/70">
1743-
Choose your comment handle to participate in discussions.
1753+
{isStaff
1754+
? "Set your team handle in the CMS before commenting."
1755+
: "Choose your comment handle to participate in discussions."}
17441756
</p>
17451757
<Link
1746-
href="/account"
1758+
href={isStaff ? "https://cms.lap.onl/admin/profile" : "/account"}
17471759
className="group inline-flex items-center gap-3 font-semibold uppercase transition-colors duration-300 hover:text-[#8a2ae3] focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-[#8a2ae3]"
17481760
>
1749-
Claim your handle
1761+
{isStaff ? "Open CMS profile" : "Claim your handle"}
17501762
<RiArrowRightLine className="text-2xl transition-transform duration-300 group-hover:translate-x-1" />
17511763
</Link>
17521764
</div>

lib/public-auth-context.tsx

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,8 +373,41 @@ export function PublicAuthProvider({ children }: { children: ReactNode }) {
373373

374374
const syncedProfile = existingProfile ? await syncPublicUser(nextUser) : null;
375375
if (!active) return;
376+
const staffData = hasStaffDoc ? staffSnapshot.data() : undefined;
377+
const staffHandle =
378+
typeof staffData?.handle === "string"
379+
? staffData.handle.trim().toLowerCase().replace(/^@+/, "")
380+
: "";
381+
const staffProfile: PublicProfile | null = staffHandle
382+
? {
383+
uid: nextUser.uid,
384+
email: nextUser.email || "",
385+
displayName:
386+
(typeof staffData?.name === "string" && staffData.name) ||
387+
syncedProfile?.displayName ||
388+
staffHandle,
389+
photoURL:
390+
(typeof staffData?.avatar === "string" && staffData.avatar) ||
391+
syncedProfile?.photoURL ||
392+
nextUser.photoURL ||
393+
"",
394+
provider: getProvider(nextUser),
395+
handle: staffHandle,
396+
status: syncedProfile?.status || "active",
397+
warningCount: syncedProfile?.warningCount,
398+
lastWarningReason: syncedProfile?.lastWarningReason,
399+
suspendedUntil: syncedProfile?.suspendedUntil,
400+
suspensionReason: syncedProfile?.suspensionReason,
401+
bannedAt: syncedProfile?.bannedAt,
402+
banReason: syncedProfile?.banReason,
403+
}
404+
: null;
376405
setUser(nextUser);
377-
setProfile(syncedProfile);
406+
setProfile(
407+
syncedProfile?.handle
408+
? syncedProfile
409+
: staffProfile || syncedProfile,
410+
);
378411
} catch (error) {
379412
console.error("Unable to sync public user profile:", error);
380413
setUser(null);

next.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const contentSecurityPolicy = [
55
"font-src 'self' data: https://fonts.gstatic.com",
66
"img-src 'self' data: blob: https:",
77
"media-src 'self' https:",
8-
"connect-src 'self' https://*.googleapis.com https://*.firebaseio.com wss://*.firebaseio.com https://*.google-analytics.com https://*.analytics.google.com https://www.googletagmanager.com https://www.google.com https://www.recaptcha.net https://auth.lap.onl https://*.cloudfunctions.net https://*.run.app",
8+
"connect-src 'self' https://*.googleapis.com https://*.firebaseio.com wss://*.firebaseio.com https://*.google-analytics.com https://*.analytics.google.com https://www.googletagmanager.com https://www.google.com https://www.recaptcha.net https://auth.lap.onl https://*.cloudfunctions.net https://*.run.app https://*.a.run.app",
99
"frame-src https://www.youtube.com https://www.youtube-nocookie.com https://accounts.google.com https://*.firebaseapp.com https://auth.lap.onl https://www.google.com/recaptcha/ https://recaptcha.google.com https://www.recaptcha.net",
1010
"worker-src 'self' blob:",
1111
"frame-ancestors 'none'",

0 commit comments

Comments
 (0)