mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-07-14 14:57:00 +10:00
refactor: remove dead code, unused exports and redundant dependencies
- drop dotenv (Node 24 process.loadEnvFile) and dompurify (only used by dead code) - delete unused ui components/hooks (card, progress, checkbox, use-confirm, use-prompt) - delete dead sanitizeHtml/sanitizeCss, url-security helpers, patch-resume tool, schema/page, createResumePatches, patch-proposal preview builder, fonts fallback helpers - inline single-caller wrappers (flags service, auth getSession, pdf renderer passthrough) - deduplicate template color helpers into shared/color-helpers - unexport 50+ internal-only symbols, remove dead export-map entries - replace hand-rolled unique()/useIsMobile with Set spread and usehooks-ts
This commit is contained in:
@@ -2,7 +2,7 @@ import type { Website } from "@reactive-resume/schema/resume/data";
|
||||
import { t } from "@lingui/core/macro";
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { TagIcon } from "@phosphor-icons/react";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import { useCallback } from "react";
|
||||
import { Input } from "@reactive-resume/ui/components/input";
|
||||
import {
|
||||
InputGroup,
|
||||
@@ -50,7 +50,7 @@ export function URLInput<TValue extends Website>({ value, onChange, hideLabelBut
|
||||
[onChange, value],
|
||||
);
|
||||
|
||||
const urlValue = useMemo(() => stripPrefix(value.url), [value.url]);
|
||||
const urlValue = stripPrefix(value.url);
|
||||
|
||||
return (
|
||||
<InputGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Trans } from "@lingui/react/macro";
|
||||
import { PasswordIcon, PencilSimpleLineIcon } from "@phosphor-icons/react";
|
||||
import { Link, useNavigate } from "@tanstack/react-router";
|
||||
import { m } from "motion/react";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import { useCallback } from "react";
|
||||
import { match } from "ts-pattern";
|
||||
import { Button } from "@reactive-resume/ui/components/button";
|
||||
import { useDialogStore } from "@/dialogs/store";
|
||||
@@ -13,7 +13,7 @@ export function PasswordSection() {
|
||||
const { openDialog } = useDialogStore();
|
||||
const { hasAccount } = useAuthAccounts();
|
||||
|
||||
const hasPassword = useMemo(() => hasAccount("credential"), [hasAccount]);
|
||||
const hasPassword = hasAccount("credential");
|
||||
|
||||
const handleUpdatePassword = useCallback(() => {
|
||||
if (hasPassword) {
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { AuthProvider } from "@reactive-resume/auth/types";
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { LinkBreakIcon, LinkIcon } from "@phosphor-icons/react";
|
||||
import { m } from "motion/react";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import { useCallback } from "react";
|
||||
import { match } from "ts-pattern";
|
||||
import { Button } from "@reactive-resume/ui/components/button";
|
||||
import { Separator } from "@reactive-resume/ui/components/separator";
|
||||
@@ -18,11 +18,11 @@ export function SocialProviderSection({ provider, name, animationDelay = 0 }: So
|
||||
const { link, unlink } = useAuthProviderActions();
|
||||
const { hasAccount, getAccountByProviderId } = useAuthAccounts();
|
||||
|
||||
const providerName = useMemo(() => name ?? getProviderName(provider), [name, provider]);
|
||||
const providerIcon = useMemo(() => getProviderIcon(provider), [provider]);
|
||||
const providerName = name ?? getProviderName(provider);
|
||||
const providerIcon = getProviderIcon(provider);
|
||||
|
||||
const account = useMemo(() => getAccountByProviderId(provider), [getAccountByProviderId, provider]);
|
||||
const isConnected = useMemo(() => hasAccount(provider), [hasAccount, provider]);
|
||||
const account = getAccountByProviderId(provider);
|
||||
const isConnected = hasAccount(provider);
|
||||
|
||||
const handleLink = useCallback(async () => {
|
||||
await link(provider);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { KeyIcon, LockOpenIcon, ToggleLeftIcon, ToggleRightIcon } from "@phosphor-icons/react";
|
||||
import { m } from "motion/react";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import { useCallback } from "react";
|
||||
import { match } from "ts-pattern";
|
||||
import { Button } from "@reactive-resume/ui/components/button";
|
||||
import { Separator } from "@reactive-resume/ui/components/separator";
|
||||
@@ -14,8 +14,8 @@ export function TwoFactorSection() {
|
||||
const { hasAccount } = useAuthAccounts();
|
||||
const { data: session } = authClient.useSession();
|
||||
|
||||
const hasPassword = useMemo(() => hasAccount("credential"), [hasAccount]);
|
||||
const hasTwoFactor = useMemo(() => session?.user.twoFactorEnabled ?? false, [session]);
|
||||
const hasPassword = hasAccount("credential");
|
||||
const hasTwoFactor = session?.user.twoFactorEnabled ?? false;
|
||||
|
||||
const handleTwoFactorAction = useCallback(() => {
|
||||
if (hasTwoFactor) {
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { act, renderHook } from "@testing-library/react";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { useIsMobile } from "./use-mobile";
|
||||
|
||||
type Listener = (event: { matches: boolean }) => void;
|
||||
|
||||
type FakeMediaQueryList = {
|
||||
matches: boolean;
|
||||
addEventListener: (type: string, fn: Listener) => void;
|
||||
removeEventListener: (type: string, fn: Listener) => void;
|
||||
__listeners: Set<Listener>;
|
||||
__set: (matches: boolean) => void;
|
||||
};
|
||||
|
||||
const createMatchMedia = (initialMatches: boolean) => {
|
||||
const mqlByQuery = new Map<string, FakeMediaQueryList>();
|
||||
|
||||
const matchMedia = vi.fn((query: string): FakeMediaQueryList => {
|
||||
let mql = mqlByQuery.get(query);
|
||||
if (mql) return mql;
|
||||
|
||||
const listeners = new Set<Listener>();
|
||||
mql = {
|
||||
matches: initialMatches,
|
||||
addEventListener: (_type, fn) => listeners.add(fn),
|
||||
removeEventListener: (_type, fn) => listeners.delete(fn),
|
||||
__listeners: listeners,
|
||||
__set: (matches: boolean) => {
|
||||
// biome-ignore lint/style/noNonNullAssertion: This closure only runs after the media query list has been initialized.
|
||||
mql!.matches = matches;
|
||||
for (const fn of listeners) fn({ matches });
|
||||
},
|
||||
};
|
||||
mqlByQuery.set(query, mql);
|
||||
return mql;
|
||||
});
|
||||
|
||||
Object.defineProperty(window, "matchMedia", {
|
||||
writable: true,
|
||||
configurable: true,
|
||||
value: matchMedia,
|
||||
});
|
||||
|
||||
return { matchMedia, getMql: (q: string) => mqlByQuery.get(q) };
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe("useIsMobile", () => {
|
||||
it("returns true when the viewport matches the mobile media query", () => {
|
||||
createMatchMedia(true);
|
||||
const { result } = renderHook(() => useIsMobile());
|
||||
expect(result.current).toBe(true);
|
||||
});
|
||||
|
||||
it("returns false when the viewport does not match the mobile media query", () => {
|
||||
createMatchMedia(false);
|
||||
const { result } = renderHook(() => useIsMobile());
|
||||
expect(result.current).toBe(false);
|
||||
});
|
||||
|
||||
it("uses the (max-width: 767px) query", () => {
|
||||
const { matchMedia } = createMatchMedia(false);
|
||||
renderHook(() => useIsMobile());
|
||||
expect(matchMedia).toHaveBeenCalledWith("(max-width: 767px)");
|
||||
});
|
||||
|
||||
it("updates when the media query change event fires", () => {
|
||||
const { getMql } = createMatchMedia(false);
|
||||
const { result } = renderHook(() => useIsMobile());
|
||||
|
||||
expect(result.current).toBe(false);
|
||||
|
||||
act(() => {
|
||||
getMql("(max-width: 767px)")?.__set(true);
|
||||
});
|
||||
|
||||
expect(result.current).toBe(true);
|
||||
});
|
||||
|
||||
it("removes the listener on unmount", () => {
|
||||
const { getMql } = createMatchMedia(false);
|
||||
const { unmount } = renderHook(() => useIsMobile());
|
||||
|
||||
const mql = getMql("(max-width: 767px)");
|
||||
expect(mql?.__listeners.size).toBe(1);
|
||||
|
||||
unmount();
|
||||
expect(mql?.__listeners.size).toBe(0);
|
||||
});
|
||||
});
|
||||
@@ -1,25 +0,0 @@
|
||||
import { useRef, useState, useSyncExternalStore } from "react";
|
||||
|
||||
const MOBILE_BREAKPOINT = 768;
|
||||
const MOBILE_QUERY = `(max-width: ${MOBILE_BREAKPOINT - 1}px)`;
|
||||
|
||||
export function useIsMobile() {
|
||||
const [mediaQueryList] = useState(() => (typeof window === "undefined" ? null : window.matchMedia(MOBILE_QUERY)));
|
||||
const latestMatchesRef = useRef(mediaQueryList?.matches ?? false);
|
||||
|
||||
return useSyncExternalStore(
|
||||
(onStoreChange) => {
|
||||
if (!mediaQueryList) return () => {};
|
||||
|
||||
const handleChange = (event: MediaQueryListEvent | { matches: boolean }) => {
|
||||
latestMatchesRef.current = event.matches;
|
||||
onStoreChange();
|
||||
};
|
||||
|
||||
mediaQueryList.addEventListener("change", handleChange);
|
||||
return () => mediaQueryList.removeEventListener("change", handleChange);
|
||||
},
|
||||
() => latestMatchesRef.current,
|
||||
() => false,
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
import "./polyfills/map-upsert";
|
||||
import { RouterProvider } from "@tanstack/react-router";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import { getRouter } from "./router";
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const originalGetOrInsert = Map.prototype.getOrInsert;
|
||||
const originalGetOrInsertComputed = Map.prototype.getOrInsertComputed;
|
||||
|
||||
const deleteMapUpsertMethods = () => {
|
||||
Reflect.deleteProperty(Map.prototype, "getOrInsert");
|
||||
Reflect.deleteProperty(Map.prototype, "getOrInsertComputed");
|
||||
};
|
||||
|
||||
const resetMapUpsertMethods = () => {
|
||||
if (originalGetOrInsert) {
|
||||
Object.defineProperty(Map.prototype, "getOrInsert", {
|
||||
value: originalGetOrInsert,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
} else {
|
||||
Reflect.deleteProperty(Map.prototype, "getOrInsert");
|
||||
}
|
||||
|
||||
if (originalGetOrInsertComputed) {
|
||||
Object.defineProperty(Map.prototype, "getOrInsertComputed", {
|
||||
value: originalGetOrInsertComputed,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
} else {
|
||||
Reflect.deleteProperty(Map.prototype, "getOrInsertComputed");
|
||||
}
|
||||
};
|
||||
|
||||
describe("map upsert polyfill", () => {
|
||||
beforeEach(() => {
|
||||
vi.resetModules();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
resetMapUpsertMethods();
|
||||
});
|
||||
|
||||
it("defines getOrInsert and getOrInsertComputed when the runtime does not provide them", async () => {
|
||||
deleteMapUpsertMethods();
|
||||
|
||||
await import("./map-upsert");
|
||||
|
||||
expect(Map.prototype.getOrInsert).toEqual(expect.any(Function));
|
||||
expect(Map.prototype.getOrInsertComputed).toEqual(expect.any(Function));
|
||||
});
|
||||
|
||||
it("does not overwrite native map upsert methods", async () => {
|
||||
const getOrInsert = () => "native";
|
||||
const getOrInsertComputed = () => "native-computed";
|
||||
Object.defineProperty(Map.prototype, "getOrInsert", { value: getOrInsert, writable: true, configurable: true });
|
||||
Object.defineProperty(Map.prototype, "getOrInsertComputed", {
|
||||
value: getOrInsertComputed,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
await import("./map-upsert");
|
||||
|
||||
expect(Map.prototype.getOrInsert).toBe(getOrInsert);
|
||||
expect(Map.prototype.getOrInsertComputed).toBe(getOrInsertComputed);
|
||||
});
|
||||
|
||||
it("returns existing values without overwriting them", async () => {
|
||||
deleteMapUpsertMethods();
|
||||
await import("./map-upsert");
|
||||
|
||||
const map = new Map<string, string | undefined>([
|
||||
["value", "existing"],
|
||||
["undefined", undefined],
|
||||
]);
|
||||
const callback = vi.fn(() => "computed");
|
||||
|
||||
expect(map.getOrInsert("value", "default")).toBe("existing");
|
||||
expect(map.getOrInsert("undefined", "default")).toBeUndefined();
|
||||
expect(map.get("value")).toBe("existing");
|
||||
expect(map.getOrInsertComputed("value", callback)).toBe("existing");
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("inserts missing values and computes lazy defaults with the key", async () => {
|
||||
deleteMapUpsertMethods();
|
||||
await import("./map-upsert");
|
||||
|
||||
const map = new Map<string, string>();
|
||||
const callback = (key: string) => `${key}-computed`;
|
||||
|
||||
expect(map.getOrInsert("value", "default")).toBe("default");
|
||||
expect(map.get("value")).toBe("default");
|
||||
expect(map.getOrInsertComputed("lazy", callback)).toBe("lazy-computed");
|
||||
expect(map.get("lazy")).toBe("lazy-computed");
|
||||
});
|
||||
|
||||
it("validates the computed callback before returning an existing value", async () => {
|
||||
deleteMapUpsertMethods();
|
||||
await import("./map-upsert");
|
||||
|
||||
const map = new Map([["value", "existing"]]);
|
||||
|
||||
expect(() => map.getOrInsertComputed("value", undefined as never)).toThrow(TypeError);
|
||||
});
|
||||
|
||||
it("passes canonical zero to the computed callback", async () => {
|
||||
deleteMapUpsertMethods();
|
||||
await import("./map-upsert");
|
||||
|
||||
const map = new Map<number, string>();
|
||||
const callback = vi.fn((key: number) => `${key}-computed`);
|
||||
|
||||
map.getOrInsertComputed(-0, callback);
|
||||
|
||||
expect(callback).toHaveBeenCalledWith(0);
|
||||
expect(Object.is(callback.mock.calls[0]?.[0], -0)).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -1,49 +0,0 @@
|
||||
declare global {
|
||||
interface Map<K, V> {
|
||||
getOrInsert(key: K, value: V): V;
|
||||
getOrInsertComputed(key: K, callbackFn: (key: K) => V): V;
|
||||
}
|
||||
}
|
||||
|
||||
const defineMapMethod = <T extends keyof Map<unknown, unknown>>(name: T, value: Map<unknown, unknown>[T]) => {
|
||||
if (typeof Map.prototype[name] === "function") return;
|
||||
|
||||
Object.defineProperty(Map.prototype, name, {
|
||||
value,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
};
|
||||
|
||||
const canonicalizeKeyedCollectionKey = <K>(key: K): K => {
|
||||
return Object.is(key, -0) ? (0 as K) : key;
|
||||
};
|
||||
|
||||
defineMapMethod("getOrInsert", function getOrInsert<K, V>(this: Map<K, V>, key: K, value: V): V {
|
||||
const canonicalKey = canonicalizeKeyedCollectionKey(key);
|
||||
|
||||
if (this.has(canonicalKey)) return this.get(canonicalKey) as V;
|
||||
|
||||
this.set(canonicalKey, value);
|
||||
|
||||
return value;
|
||||
});
|
||||
|
||||
defineMapMethod("getOrInsertComputed", function getOrInsertComputed<
|
||||
K,
|
||||
V,
|
||||
>(this: Map<K, V>, key: K, callbackFn: (key: K) => V): V {
|
||||
if (typeof callbackFn !== "function")
|
||||
throw new TypeError("Map.prototype.getOrInsertComputed callback must be a function");
|
||||
|
||||
const canonicalKey = canonicalizeKeyedCollectionKey(key);
|
||||
|
||||
if (this.has(canonicalKey)) return this.get(canonicalKey) as V;
|
||||
|
||||
const value = callbackFn(canonicalKey);
|
||||
this.set(canonicalKey, value);
|
||||
|
||||
return value;
|
||||
});
|
||||
|
||||
export {};
|
||||
@@ -5,6 +5,7 @@ import type { Locale } from "@reactive-resume/utils/locale";
|
||||
import type { QueryClient } from "@tanstack/react-query";
|
||||
import type { orpc } from "@/libs/orpc/client";
|
||||
import type { Theme } from "@/libs/theme";
|
||||
import { DirectionProvider } from "@base-ui/react/direction-provider";
|
||||
import { i18n } from "@lingui/core";
|
||||
import { I18nProvider } from "@lingui/react";
|
||||
import { IconContext } from "@phosphor-icons/react";
|
||||
@@ -13,7 +14,6 @@ import { QueryClientProvider } from "@tanstack/react-query";
|
||||
import { createRootRouteWithContext, HeadContent, Outlet } from "@tanstack/react-router";
|
||||
import { domAnimation, LazyMotion, MotionConfig } from "motion/react";
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { DirectionProvider } from "@reactive-resume/ui/components/direction";
|
||||
import { Toaster } from "@reactive-resume/ui/components/sonner";
|
||||
import { TooltipProvider } from "@reactive-resume/ui/components/tooltip";
|
||||
import { BreakpointIndicator } from "@/components/layout/breakpoint-indicator";
|
||||
|
||||
@@ -20,7 +20,6 @@ import {
|
||||
TranslateIcon,
|
||||
} from "@phosphor-icons/react";
|
||||
import { m } from "motion/react";
|
||||
import { useMemo } from "react";
|
||||
import { cn } from "@reactive-resume/utils/style";
|
||||
|
||||
type Feature = {
|
||||
@@ -167,7 +166,7 @@ function FeatureCard({ icon: Icon, title, description }: FeatureCardProps) {
|
||||
}
|
||||
|
||||
export function Features() {
|
||||
const features = useMemo(() => getFeatures(), []);
|
||||
const features = getFeatures();
|
||||
|
||||
return (
|
||||
<section id="features">
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import type { Layout, usePanelRef } from "react-resizable-panels";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import { useWindowSize } from "usehooks-ts";
|
||||
import { useMediaQuery, useWindowSize } from "usehooks-ts";
|
||||
import { create } from "zustand/react";
|
||||
import { useIsMobile } from "@/hooks/use-mobile";
|
||||
|
||||
type PanelImperativeHandle = ReturnType<typeof usePanelRef>;
|
||||
|
||||
@@ -102,7 +101,7 @@ type UseBuilderSidebarReturn = {
|
||||
};
|
||||
|
||||
export function useBuilderSidebar<T = UseBuilderSidebarReturn>(selector?: (builder: UseBuilderSidebarReturn) => T): T {
|
||||
const isMobile = useIsMobile();
|
||||
const isMobile = useMediaQuery("(max-width: 767px)", { initializeWithValue: false });
|
||||
const { width } = useWindowSize();
|
||||
|
||||
const { maxSidebarSize, minSidebarSize, collapsedSidebarSize, expandSize, groupResizeBehavior } =
|
||||
|
||||
@@ -6,6 +6,7 @@ import { createFileRoute, Outlet, redirect } from "@tanstack/react-router";
|
||||
import Cookies from "js-cookie";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { usePanelRef } from "react-resizable-panels";
|
||||
import { useMediaQuery } from "usehooks-ts";
|
||||
import { ResizableGroup, ResizablePanel, ResizableSeparator } from "@reactive-resume/ui/components/resizable";
|
||||
import {
|
||||
useBuilderResumeUpdateSubscription,
|
||||
@@ -14,7 +15,6 @@ import {
|
||||
useResumeCleanup,
|
||||
useResumeStore,
|
||||
} from "@/features/resume/builder/draft";
|
||||
import { useIsMobile } from "@/hooks/use-mobile";
|
||||
import { orpc } from "@/libs/orpc/client";
|
||||
import { createNoindexFollowMeta } from "@/libs/seo";
|
||||
import { BuilderHeader } from "./-components/header";
|
||||
@@ -94,7 +94,7 @@ type BuilderLayoutShellProps = React.ComponentProps<"div"> & {
|
||||
};
|
||||
|
||||
function BuilderLayoutShell({ initialLayout }: BuilderLayoutShellProps) {
|
||||
const isMobile = useIsMobile();
|
||||
const isMobile = useMediaQuery("(max-width: 767px)", { initializeWithValue: false });
|
||||
const canPersistLayoutRef = useRef(false);
|
||||
|
||||
const leftSidebarRef = usePanelRef();
|
||||
|
||||
Reference in New Issue
Block a user