Commit d711d724 authored by Johnny's avatar Johnny

chore: clean up unused imports and parameters across components

parent 0ad75b8f
...@@ -4,7 +4,7 @@ import { useCallback } from "react"; ...@@ -4,7 +4,7 @@ import { useCallback } from "react";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import { useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
import { useInstance } from "@/contexts/InstanceContext"; import { useInstance } from "@/contexts/InstanceContext";
import { memoKeys, useDeleteMemo, useUpdateMemo } from "@/hooks/useMemoQueries"; import { useDeleteMemo, useUpdateMemo } from "@/hooks/useMemoQueries";
import useNavigateTo from "@/hooks/useNavigateTo"; import useNavigateTo from "@/hooks/useNavigateTo";
import { userKeys } from "@/hooks/useUserQueries"; import { userKeys } from "@/hooks/useUserQueries";
import { State } from "@/types/proto/api/v1/common_pb"; import { State } from "@/types/proto/api/v1/common_pb";
......
...@@ -3,7 +3,7 @@ import { timestampDate } from "@bufbuild/protobuf/wkt"; ...@@ -3,7 +3,7 @@ import { timestampDate } from "@bufbuild/protobuf/wkt";
import { isEqual } from "lodash-es"; import { isEqual } from "lodash-es";
import { CheckCircleIcon, Code2Icon, HashIcon, LinkIcon } from "lucide-react"; import { CheckCircleIcon, Code2Icon, HashIcon, LinkIcon } from "lucide-react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { Memo, Memo_Property, Memo_PropertySchema, MemoRelation_Type } from "@/types/proto/api/v1/memo_service_pb"; import { Memo, Memo_PropertySchema, MemoRelation_Type } from "@/types/proto/api/v1/memo_service_pb";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import MemoRelationForceGraph from "../MemoRelationForceGraph"; import MemoRelationForceGraph from "../MemoRelationForceGraph";
......
...@@ -25,7 +25,7 @@ export const LocationDialog = ({ ...@@ -25,7 +25,7 @@ export const LocationDialog = ({
open, open,
onOpenChange, onOpenChange,
state, state,
locationInitialized, locationInitialized: _locationInitialized,
onPositionChange, onPositionChange,
onUpdateCoordinate, onUpdateCoordinate,
onPlaceholderChange, onPlaceholderChange,
......
...@@ -7,7 +7,7 @@ interface UseKeyboardOptions { ...@@ -7,7 +7,7 @@ interface UseKeyboardOptions {
onToggleFocusMode?: () => void; onToggleFocusMode?: () => void;
} }
export const useKeyboard = (editorRef: React.RefObject<EditorRefActions | null>, options: UseKeyboardOptions) => { export const useKeyboard = (_editorRef: React.RefObject<EditorRefActions | null>, options: UseKeyboardOptions) => {
useEffect(() => { useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => { const handleKeyDown = (event: KeyboardEvent) => {
// Cmd/Ctrl + Enter to save // Cmd/Ctrl + Enter to save
......
...@@ -5,14 +5,7 @@ import { memoServiceClient } from "@/connect"; ...@@ -5,14 +5,7 @@ import { memoServiceClient } from "@/connect";
import { DEFAULT_LIST_MEMOS_PAGE_SIZE } from "@/helpers/consts"; import { DEFAULT_LIST_MEMOS_PAGE_SIZE } from "@/helpers/consts";
import { extractUserIdFromName } from "@/helpers/resource-names"; import { extractUserIdFromName } from "@/helpers/resource-names";
import useCurrentUser from "@/hooks/useCurrentUser"; import useCurrentUser from "@/hooks/useCurrentUser";
import { import { Memo, MemoRelation, MemoRelation_MemoSchema, MemoRelation_Type, MemoRelationSchema } from "@/types/proto/api/v1/memo_service_pb";
Memo,
MemoRelation,
MemoRelation_Memo,
MemoRelation_MemoSchema,
MemoRelation_Type,
MemoRelationSchema,
} from "@/types/proto/api/v1/memo_service_pb";
interface UseLinkMemoParams { interface UseLinkMemoParams {
isOpen: boolean; isOpen: boolean;
......
import type { LocalFile } from "@/components/memo-metadata"; import type { LocalFile } from "@/components/memo-metadata";
import type { Attachment } from "@/types/proto/api/v1/attachment_service_pb"; import type { Attachment } from "@/types/proto/api/v1/attachment_service_pb";
import type { Location, MemoRelation } from "@/types/proto/api/v1/memo_service_pb"; import type { MemoRelation } from "@/types/proto/api/v1/memo_service_pb";
import type { EditorAction, EditorState, LoadingKey } from "./types"; import type { EditorAction, EditorState, LoadingKey } from "./types";
export const editorActions = { export const editorActions = {
......
...@@ -2,7 +2,7 @@ import { create } from "@bufbuild/protobuf"; ...@@ -2,7 +2,7 @@ import { create } from "@bufbuild/protobuf";
import { FieldMaskSchema } from "@bufbuild/protobuf/wkt"; import { FieldMaskSchema } from "@bufbuild/protobuf/wkt";
import { sortBy } from "lodash-es"; import { sortBy } from "lodash-es";
import { MoreVerticalIcon, PlusIcon } from "lucide-react"; import { MoreVerticalIcon, PlusIcon } from "lucide-react";
import React, { useState } from "react"; import { useState } from "react";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import ConfirmDialog from "@/components/ConfirmDialog"; import ConfirmDialog from "@/components/ConfirmDialog";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
......
import { create } from "@bufbuild/protobuf";
import { isEqual } from "lodash-es"; import { isEqual } from "lodash-es";
import { XIcon } from "lucide-react"; import { XIcon } from "lucide-react";
import { useState } from "react"; import { useState } from "react";
...@@ -12,7 +11,6 @@ import { useInstance } from "@/contexts/InstanceContext"; ...@@ -12,7 +11,6 @@ import { useInstance } from "@/contexts/InstanceContext";
import { convertFileToBase64 } from "@/helpers/utils"; import { convertFileToBase64 } from "@/helpers/utils";
import useCurrentUser from "@/hooks/useCurrentUser"; import useCurrentUser from "@/hooks/useCurrentUser";
import { useUpdateUser } from "@/hooks/useUserQueries"; import { useUpdateUser } from "@/hooks/useUserQueries";
import { User as UserPb, UserSchema } from "@/types/proto/api/v1/user_service_pb";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import UserAvatar from "./UserAvatar"; import UserAvatar from "./UserAvatar";
......
...@@ -89,8 +89,8 @@ const UserMenu = (props: Props) => { ...@@ -89,8 +89,8 @@ const UserMenu = (props: Props) => {
try { try {
// Then clear user-specific localStorage items // Then clear user-specific localStorage items
// Preserve app-wide settings like theme // Preserve app-wide settings (theme, locale, view preferences, tag view settings)
const keysToPreserve = ["memos-theme", "tag-view-as-tree", "tag-tree-auto-expand", "viewStore"]; const keysToPreserve = ["memos-theme", "memos-locale", "memos-view-setting", "tag-view-as-tree", "tag-tree-auto-expand"];
const keysToRemove: string[] = []; const keysToRemove: string[] = [];
for (let i = 0; i < localStorage.length; i++) { for (let i = 0; i < localStorage.length; i++) {
...@@ -105,8 +105,8 @@ const UserMenu = (props: Props) => { ...@@ -105,8 +105,8 @@ const UserMenu = (props: Props) => {
// Ignore errors from localStorage operations // Ignore errors from localStorage operations
} }
// Always redirect to auth page // Always redirect to auth page (use replace to prevent back navigation)
window.location.href = Routes.AUTH; window.location.replace(Routes.AUTH);
}; };
return ( return (
......
...@@ -2,8 +2,6 @@ import { timestampDate } from "@bufbuild/protobuf/wkt"; ...@@ -2,8 +2,6 @@ import { timestampDate } from "@bufbuild/protobuf/wkt";
import { Code, ConnectError, createClient, type Interceptor } from "@connectrpc/connect"; import { Code, ConnectError, createClient, type Interceptor } from "@connectrpc/connect";
import { createConnectTransport } from "@connectrpc/connect-web"; import { createConnectTransport } from "@connectrpc/connect-web";
import { getAccessToken, setAccessToken } from "./auth-state"; import { getAccessToken, setAccessToken } from "./auth-state";
import { getInstanceConfig } from "./instance-config";
import { ROUTES } from "./router/routes";
import { ActivityService } from "./types/proto/api/v1/activity_service_pb"; import { ActivityService } from "./types/proto/api/v1/activity_service_pb";
import { AttachmentService } from "./types/proto/api/v1/attachment_service_pb"; import { AttachmentService } from "./types/proto/api/v1/attachment_service_pb";
import { AuthService } from "./types/proto/api/v1/auth_service_pb"; import { AuthService } from "./types/proto/api/v1/auth_service_pb";
...@@ -12,6 +10,7 @@ import { InstanceService } from "./types/proto/api/v1/instance_service_pb"; ...@@ -12,6 +10,7 @@ import { InstanceService } from "./types/proto/api/v1/instance_service_pb";
import { MemoService } from "./types/proto/api/v1/memo_service_pb"; import { MemoService } from "./types/proto/api/v1/memo_service_pb";
import { ShortcutService } from "./types/proto/api/v1/shortcut_service_pb"; import { ShortcutService } from "./types/proto/api/v1/shortcut_service_pb";
import { UserService } from "./types/proto/api/v1/user_service_pb"; import { UserService } from "./types/proto/api/v1/user_service_pb";
import { redirectOnAuthFailure } from "./utils/auth-redirect";
// ============================================================================ // ============================================================================
// Constants // Constants
...@@ -20,19 +19,6 @@ import { UserService } from "./types/proto/api/v1/user_service_pb"; ...@@ -20,19 +19,6 @@ import { UserService } from "./types/proto/api/v1/user_service_pb";
const RETRY_HEADER = "X-Retry"; const RETRY_HEADER = "X-Retry";
const RETRY_HEADER_VALUE = "true"; const RETRY_HEADER_VALUE = "true";
const ROUTE_CONFIG = {
// Routes accessible without authentication (uses prefix matching)
public: [
ROUTES.AUTH, // Authentication pages
ROUTES.EXPLORE, // Explore page
"/u/", // User profile pages (dynamic)
"/memos/", // Individual memo detail pages (dynamic)
],
// Routes that require authentication (uses exact matching)
private: [ROUTES.ROOT, ROUTES.ATTACHMENTS, ROUTES.INBOX, ROUTES.ARCHIVED, ROUTES.SETTING],
} as const;
// ============================================================================ // ============================================================================
// Token Refresh State Management // Token Refresh State Management
// ============================================================================ // ============================================================================
...@@ -60,42 +46,6 @@ const createTokenRefreshManager = () => { ...@@ -60,42 +46,6 @@ const createTokenRefreshManager = () => {
const tokenRefreshManager = createTokenRefreshManager(); const tokenRefreshManager = createTokenRefreshManager();
// ============================================================================
// Route Access Control
// ============================================================================
function isPublicRoute(path: string): boolean {
return ROUTE_CONFIG.public.some((route) => path.startsWith(route));
}
function isPrivateRoute(path: string): boolean {
return (ROUTE_CONFIG.private as readonly string[]).includes(path);
}
function getAuthFailureRedirect(currentPath: string): string | null {
if (isPublicRoute(currentPath)) {
return null;
}
if (getInstanceConfig().memoRelatedSetting.disallowPublicVisibility) {
return ROUTES.AUTH;
}
if (isPrivateRoute(currentPath)) {
return ROUTES.EXPLORE;
}
return null;
}
function performRedirect(redirectUrl: string | null): void {
if (redirectUrl) {
// Use replace() instead of href to prevent back button from showing cached sensitive data
// This removes the current page from browser history after authentication failure
window.location.replace(redirectUrl);
}
}
// ============================================================================ // ============================================================================
// Token Refresh // Token Refresh
// ============================================================================ // ============================================================================
...@@ -165,8 +115,7 @@ const authInterceptor: Interceptor = (next) => async (req) => { ...@@ -165,8 +115,7 @@ const authInterceptor: Interceptor = (next) => async (req) => {
req.header.set(RETRY_HEADER, RETRY_HEADER_VALUE); req.header.set(RETRY_HEADER, RETRY_HEADER_VALUE);
return await next(req); return await next(req);
} catch (refreshError) { } catch (refreshError) {
const redirectUrl = getAuthFailureRedirect(window.location.pathname); redirectOnAuthFailure();
performRedirect(redirectUrl);
throw refreshError; throw refreshError;
} }
} }
......
...@@ -32,4 +32,3 @@ const useMediaQuery = (breakpoint: Breakpoint): boolean => { ...@@ -32,4 +32,3 @@ const useMediaQuery = (breakpoint: Breakpoint): boolean => {
}; };
export default useMediaQuery; export default useMediaQuery;
import { Suspense, useEffect, useMemo, useState } from "react"; import { Suspense, useEffect, useMemo } from "react";
import { Outlet, useLocation, useSearchParams } from "react-router-dom"; import { Outlet, useLocation, useSearchParams } from "react-router-dom";
import usePrevious from "react-use/lib/usePrevious"; import usePrevious from "react-use/lib/usePrevious";
import Navigation from "@/components/Navigation"; import Navigation from "@/components/Navigation";
...@@ -8,7 +8,7 @@ import useCurrentUser from "@/hooks/useCurrentUser"; ...@@ -8,7 +8,7 @@ import useCurrentUser from "@/hooks/useCurrentUser";
import useMediaQuery from "@/hooks/useMediaQuery"; import useMediaQuery from "@/hooks/useMediaQuery";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import Loading from "@/pages/Loading"; import Loading from "@/pages/Loading";
import { Routes } from "@/router"; import { redirectOnAuthFailure } from "@/utils/auth-redirect";
const RootLayout = () => { const RootLayout = () => {
const location = useLocation(); const location = useLocation();
...@@ -17,25 +17,14 @@ const RootLayout = () => { ...@@ -17,25 +17,14 @@ const RootLayout = () => {
const currentUser = useCurrentUser(); const currentUser = useCurrentUser();
const { memoRelatedSetting } = useInstance(); const { memoRelatedSetting } = useInstance();
const { removeFilter } = useMemoFilterContext(); const { removeFilter } = useMemoFilterContext();
const [initialized, setInitialized] = useState(false);
const pathname = useMemo(() => location.pathname, [location.pathname]); const pathname = useMemo(() => location.pathname, [location.pathname]);
const prevPathname = usePrevious(pathname); const prevPathname = usePrevious(pathname);
useEffect(() => { useEffect(() => {
if (!currentUser) { if (!currentUser && memoRelatedSetting.disallowPublicVisibility) {
// If disallowPublicVisibility is enabled, redirect to login redirectOnAuthFailure();
if (memoRelatedSetting.disallowPublicVisibility) {
window.location.replace(Routes.AUTH);
return;
} else if (
([Routes.ROOT, Routes.ATTACHMENTS, Routes.INBOX, Routes.ARCHIVED, Routes.SETTING] as string[]).includes(location.pathname)
) {
window.location.replace(Routes.EXPLORE);
return;
}
} }
setInitialized(true); }, [currentUser, memoRelatedSetting.disallowPublicVisibility]);
}, [currentUser, memoRelatedSetting.disallowPublicVisibility, location.pathname]);
useEffect(() => { useEffect(() => {
// When the route changes and there is no filter in the search params, remove all filters // When the route changes and there is no filter in the search params, remove all filters
...@@ -44,9 +33,7 @@ const RootLayout = () => { ...@@ -44,9 +33,7 @@ const RootLayout = () => {
} }
}, [prevPathname, pathname, searchParams, removeFilter]); }, [prevPathname, pathname, searchParams, removeFilter]);
return !initialized ? ( return (
<Loading />
) : (
<div className="w-full min-h-full flex flex-row justify-center items-start sm:pl-16"> <div className="w-full min-h-full flex flex-row justify-center items-start sm:pl-16">
{sm && ( {sm && (
<div <div
......
...@@ -57,7 +57,7 @@ const MemoDetail = () => { ...@@ -57,7 +57,7 @@ const MemoDetail = () => {
setShowCommentEditor(true); setShowCommentEditor(true);
}; };
const handleCommentCreated = async (memoCommentName: string) => { const handleCommentCreated = async (_memoCommentName: string) => {
// React Query will auto-refetch due to invalidation in the mutation // React Query will auto-refetch due to invalidation in the mutation
setShowCommentEditor(false); setShowCommentEditor(false);
}; };
......
import { getInstanceConfig } from "@/instance-config";
import { ROUTES } from "@/router/routes";
const PUBLIC_ROUTES = [
ROUTES.AUTH, // Authentication pages
ROUTES.EXPLORE, // Explore page
"/u/", // User profile pages (dynamic)
"/memos/", // Individual memo detail pages (dynamic)
] as const;
const PRIVATE_ROUTES = [ROUTES.ROOT, ROUTES.ATTACHMENTS, ROUTES.INBOX, ROUTES.ARCHIVED, ROUTES.SETTING] as const;
function isPublicRoute(path: string): boolean {
return PUBLIC_ROUTES.some((route) => path.startsWith(route));
}
function isPrivateRoute(path: string): boolean {
return PRIVATE_ROUTES.includes(path as any);
}
export function redirectOnAuthFailure(): void {
const currentPath = window.location.pathname;
// Don't redirect if it's a public route
if (isPublicRoute(currentPath)) {
return;
}
const disallowPublicVisibility = getInstanceConfig().memoRelatedSetting.disallowPublicVisibility;
const target = disallowPublicVisibility ? ROUTES.AUTH : ROUTES.EXPLORE;
// Only redirect if it's a private route or disallowPublicVisibility is enabled
if (disallowPublicVisibility || isPrivateRoute(currentPath)) {
window.location.replace(target);
}
}
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
"esModuleInterop": false, "esModuleInterop": false,
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"strict": true, "strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"module": "ESNext", "module": "ESNext",
"moduleResolution": "Node", "moduleResolution": "Node",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment