From bae1ad06d57e834e654093416992fc68a47e5ffe Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 10 Mar 2026 12:58:22 +0000 Subject: [PATCH 1/5] fix: resolve critical crashes in preview page and edit mode - Fix #37: Add error state handling in PreviewClient when resumeQuery or usernameQuery fails, showing a user-friendly error message with a refresh button instead of an infinite loading spinner or crash - Fix #36: Prevent crash in Header.tsx when website URL is malformed by wrapping new URL() in a try/catch block - Fix #36: Prevent crash in EditResume when resume.header.skills is undefined/null (legacy data) by using nullish coalescing (?? []) in all skills array operations https://claude.ai/code/session_017oUgH1Y6iZmosXcmutVYKF --- app/(private)/preview/client.tsx | 15 +++++++++++++++ components/resume/Header.tsx | 8 +++++++- components/resume/editing/EditResume.tsx | 10 +++++----- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/app/(private)/preview/client.tsx b/app/(private)/preview/client.tsx index 7ab0c99..2e86e38 100644 --- a/app/(private)/preview/client.tsx +++ b/app/(private)/preview/client.tsx @@ -88,6 +88,21 @@ export default function PreviewClient({ messageTip }: { messageTip?: string }) { setHasUnsavedChanges(true); }; + if (resumeQuery.isError || usernameQuery.isError) { + const errorMessage = + resumeQuery.error instanceof Error + ? resumeQuery.error.message + : usernameQuery.error instanceof Error + ? usernameQuery.error.message + : 'Something went wrong. Please refresh the page.'; + return ( +
+

{errorMessage}

+ +
+ ); + } + if ( resumeQuery.isLoading || usernameQuery.isLoading || diff --git a/components/resume/Header.tsx b/components/resume/Header.tsx index 5f07d64..a44a810 100644 --- a/components/resume/Header.tsx +++ b/components/resume/Header.tsx @@ -178,7 +178,13 @@ export function Header({ className="underline hover:text-foreground/70" href={socialLinks.website} > - {new URL(socialLinks.website).hostname} + {(() => { + try { + return new URL(socialLinks.website).hostname; + } catch { + return socialLinks.website; + } + })()} diff --git a/components/resume/editing/EditResume.tsx b/components/resume/editing/EditResume.tsx index de50e63..72fdc04 100644 --- a/components/resume/editing/EditResume.tsx +++ b/components/resume/editing/EditResume.tsx @@ -20,14 +20,14 @@ export const EditResume = ({ const [isAddSkillDialogOpen, setIsAddSkillDialogOpen] = useState(false); const handleAddSkill = (skillToAdd: string) => { - if (resume.header.skills.includes(skillToAdd)) { + if ((resume.header.skills ?? []).includes(skillToAdd)) { toast.warning('This skill is already added.'); } else { onChangeResume({ ...resume, header: { ...resume.header, - skills: [...resume.header.skills, skillToAdd], + skills: [...(resume.header.skills ?? []), skillToAdd], }, }); toast.success('Skill added successfully.'); @@ -357,13 +357,13 @@ export const EditResume = ({

Skills

- {resume.header.skills.map((skill, index) => ( + {(resume.header.skills ?? []).map((skill, index) => ( { - const newSkills = [...resume.header.skills]; + const newSkills = [...(resume.header.skills ?? [])]; newSkills[index] = updatedSkill; onChangeResume({ ...resume, @@ -374,7 +374,7 @@ export const EditResume = ({ }); }} onDelete={(index) => { - const newSkills = [...resume.header.skills]; + const newSkills = [...(resume.header.skills ?? [])]; newSkills.splice(index, 1); onChangeResume({ ...resume, From f14ac5ef9ffbb3e571c8630bfb58f10aaf15c429 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 10 Mar 2026 13:04:02 +0000 Subject: [PATCH 2/5] feat: add dark/light/system theme toggle and fix text formatting - Add ThemeToggle component with Sun/Moon/Monitor icons dropdown (Light, Dark, System options) using next-themes + existing CSS vars - Wire ThemeProvider into layout.tsx with suppressHydrationWarning - Place ThemeToggle in TopMenu header, visible for all users - Fix #31/#33: add whitespace-pre-wrap to Summary component so multi-line descriptions render with correct line breaks https://claude.ai/code/session_017oUgH1Y6iZmosXcmutVYKF --- app/layout.tsx | 9 +++++--- components/ThemeToggle.tsx | 41 +++++++++++++++++++++++++++++++++++ components/TopMenu.tsx | 6 +++-- components/resume/Summary.tsx | 2 +- 4 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 components/ThemeToggle.tsx diff --git a/app/layout.tsx b/app/layout.tsx index b5ea15d..175c6de 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -4,6 +4,7 @@ import { ClerkProvider } from '@clerk/nextjs'; import './globals.css'; import { Toaster } from '@/components/ui/sonner'; import { ReactQueryClientProvider } from '@/components/ReactQueryClientProvider'; +import { ThemeProvider } from '@/components/theme-provider'; import { Metadata } from 'next'; import PlausibleProvider from 'next-plausible'; @@ -28,7 +29,7 @@ export default function RootLayout({ - + {/* {process.env.NODE_ENV === "development" && (