Skip to content

Commit 6cc351f

Browse files
committed
chore(eslint): update ESLint configuration for better compatibility
Add `@eslint/js` recommended configuration to improve linting standards. Include `@next/eslint-plugin-next` and `eslint-plugin-next` to enhance Next.js specific linting capabilities. Adjust formatting for consistency and readability. refactor(files.ts): introduce DriveFile interface for better type safety Define a `DriveFile` interface to improve type safety and readability when handling Google Drive file data. This change reduces the use of `any` type and clarifies the structure of file objects. feat(Footer.tsx): display current time using useEffect hook Add `useEffect` to set the current time in the footer component, improving the accuracy of the displayed timestamp. This change ensures the time is set once the component mounts. refactor(form.tsx): destructure props for better readability Destructure props in `FormItem` and `FormLabel` components to enhance readability and maintainability. This change clarifies which props are being used and passed down. docs(useLoading.ts): improve documentation for useLoading hook Enhance the documentation for the `useLoading` hook to clarify its usage and behavior, especially regarding dependency management in async mode. This change aims to prevent misuse and improve developer experience. refactor(errors.ts): improve type safety in withErrorHandler Refine the `withErrorHandler` function to use `unknown` instead of `any` for better type safety. This change aligns with TypeScript best practices and improves code reliability.
1 parent 8101eeb commit 6cc351f

File tree

8 files changed

+134
-88
lines changed

8 files changed

+134
-88
lines changed

eslint.config.mjs

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
1+
import js from "@eslint/js";
12
import { FlatCompat } from "@eslint/eslintrc";
23

34
const compat = new FlatCompat({
5+
// import.meta.dirname is available after Node.js v20.11.0
46
baseDirectory: import.meta.dirname,
7+
recommendedConfig: js.configs.recommended,
58
});
69

710
const eslintConfig = [
811
// Use Next.js recommended configuration as base
912
...compat.config({
1013
extends: [
1114
"next/core-web-vitals", // Includes Next.js specific rules + React rules
12-
"next/typescript", // TypeScript specific rules for Next.js
13-
"prettier", // Disable ESLint rules that conflict with Prettier
15+
"next/typescript", // TypeScript specific rules for Next.js
16+
"prettier", // Disable ESLint rules that conflict with Prettier
1417
],
1518
}),
1619
// Global ignores (replaces .eslintignore)
@@ -21,28 +24,28 @@ const eslintConfig = [
2124
"**/.pnp",
2225
"**/.pnp.js",
2326
"**/.yarn/**",
24-
27+
2528
// Build outputs
2629
"**/.next/**",
2730
"**/out/**",
2831
"**/build/**",
2932
"**/dist/**",
3033
"**/.vercel/**",
3134
"**/storybook-static/**",
32-
35+
3336
// Testing & Coverage
3437
"**/coverage/**",
3538
"**/.nyc_output/**",
3639
"**/test-results/**",
3740
"**/playwright-report/**",
3841
"**/playwright/.cache/**",
39-
42+
4043
// Configuration files
4144
"**/*.config.js",
4245
"**/*.config.mjs",
4346
"**/*.config.ts",
4447
"**/commitlint.config.js",
45-
48+
4649
// Generated files
4750
"**/*.min.js",
4851
"**/*.min.css",
@@ -51,12 +54,12 @@ const eslintConfig = [
5154
"**/public/worker-*.js",
5255
"**/public/fallback-*.js",
5356
"**/public/precache.*.js",
54-
57+
5558
// TypeScript
5659
"**/*.d.ts",
5760
"**/next-env.d.ts",
5861
"**/*.tsbuildinfo",
59-
62+
6063
// Logs
6164
"**/logs/**",
6265
"**/*.log",
@@ -65,36 +68,36 @@ const eslintConfig = [
6568
"**/yarn-error.log*",
6669
"**/pnpm-debug.log*",
6770
"**/lerna-debug.log*",
68-
71+
6972
// OS files
7073
"**/.DS_Store",
7174
"**/Thumbs.db",
72-
75+
7376
// Security
7477
"**/*.pem",
7578
"**/*.key",
7679
"**/*.crt",
77-
80+
7881
// Environment
7982
"**/.env*",
80-
83+
8184
// Temporary & cache
8285
"**/.cache/**",
8386
"**/.parcel-cache/**",
8487
"**/tmp/**",
8588
"**/temp/**",
8689
"**/*.tmp",
8790
"**/*.temp",
88-
91+
8992
// Package files
9093
"**/package-lock.json",
9194
"**/yarn.lock",
9295
"**/pnpm-lock.yaml",
93-
96+
9497
// Documentation
9598
"**/*.md",
9699
"**/LICENSE",
97-
100+
98101
// Misc
99102
"**/.eslintcache",
100103
"**/.prettierignore",
@@ -106,34 +109,43 @@ const eslintConfig = [
106109
rules: {
107110
// TypeScript rules (warnings for gradual adoption)
108111
"@typescript-eslint/no-explicit-any": "warn",
109-
"@typescript-eslint/no-unused-vars": ["warn", {
110-
argsIgnorePattern: "^_",
111-
varsIgnorePattern: "^_",
112-
caughtErrorsIgnorePattern: "^_",
113-
}],
114-
"@typescript-eslint/consistent-type-imports": ["warn", {
115-
prefer: "type-imports",
116-
fixStyle: "inline-type-imports",
117-
}],
118-
112+
"@typescript-eslint/no-unused-vars": [
113+
"warn",
114+
{
115+
argsIgnorePattern: "^_",
116+
varsIgnorePattern: "^_",
117+
caughtErrorsIgnorePattern: "^_",
118+
},
119+
],
120+
"@typescript-eslint/consistent-type-imports": [
121+
"warn",
122+
{
123+
prefer: "type-imports",
124+
fixStyle: "inline-type-imports",
125+
},
126+
],
127+
119128
// React best practices
120129
// Allow both arrow functions and function declarations
121130
"react/function-component-definition": "off",
122-
131+
123132
// Next.js specific rules
124133
"@next/next/no-html-link-for-pages": "error",
125134
"@next/next/no-img-element": "warn", // Warn instead of error for gradual migration
126-
135+
127136
// General code quality
128-
"no-console": ["warn", {
129-
allow: ["warn", "error", "info", "debug"] // Allow more console methods in development
130-
}],
137+
"no-console": [
138+
"warn",
139+
{
140+
allow: ["warn", "error", "info", "debug"], // Allow more console methods in development
141+
},
142+
],
131143
"prefer-const": "error",
132144
"no-var": "error",
133145
"object-shorthand": "warn",
134146
"prefer-arrow-callback": "off", // Turn off to allow function expressions
135147
"prefer-template": "warn",
136-
148+
137149
// Import rules (when import plugin is available)
138150
"import/first": "off",
139151
"import/newline-after-import": "off",

package-lock.json

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
"@commitlint/cli": "^19.8.1",
9595
"@commitlint/config-conventional": "^19.8.1",
9696
"@eslint/js": "^9.30.1",
97+
"@next/eslint-plugin-next": "^15.3.5",
9798
"@tailwindcss/postcss": "^4.1.11",
9899
"@types/cors": "^2.8.19",
99100
"@types/eslint": "^9.6.1",
@@ -114,6 +115,7 @@
114115
"eslint-config-prettier": "^10.1.5",
115116
"eslint-plugin-import": "^2.32.0",
116117
"eslint-plugin-jsx-a11y": "^6.10.2",
118+
"eslint-plugin-next": "^0.0.0",
117119
"eslint-plugin-react": "^7.37.5",
118120
"eslint-plugin-react-hooks": "^5.2.0",
119121
"husky": "^9.1.7",

src/actions/files.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ import { encryptionService, gdrive } from "@/lib/utils.server";
1010

1111
import { ValidatePaths } from "./paths";
1212

13+
interface DriveFile {
14+
mimeType?: string;
15+
size?: string | number;
16+
fileExtension?: string;
17+
name?: string;
18+
}
19+
1320
/**
1421
* List files in a folder
1522
* @param {object} options
@@ -577,19 +584,25 @@ export async function GetStorageInfo(): Promise<
577584
pageToken: pageToken || undefined,
578585
});
579586

580-
if (response && (response as any).data.files) {
581-
for (const file of (response as any).data.files) {
582-
if (file.mimeType === "application/vnd.google-apps.folder") {
587+
if (
588+
response &&
589+
(response as { data: { files: unknown[]; nextPageToken?: string } })
590+
.data.files
591+
) {
592+
for (const file of (response as { data: { files: unknown[] } }).data
593+
.files) {
594+
const f = file as DriveFile;
595+
if (f.mimeType === "application/vnd.google-apps.folder") {
583596
totalFolders++;
584597
} else {
585598
totalFiles++;
586-
if (file.size) {
587-
const fileSize = Number(file.size);
599+
if (f.size) {
600+
const fileSize = Number(f.size);
588601
totalSize += fileSize;
589602

590603
// Categorize by file type
591-
const extension = file.fileExtension || "no-extension";
592-
const mimeType = file.mimeType || "unknown";
604+
const extension = f.fileExtension || "no-extension";
605+
const mimeType = f.mimeType || "unknown";
593606

594607
let category = "other";
595608
if (mimeType.startsWith("image/")) category = "images";
@@ -619,7 +632,8 @@ export async function GetStorageInfo(): Promise<
619632
}
620633
}
621634

622-
pageToken = (response as any).data.nextPageToken;
635+
pageToken = (response as { data: { nextPageToken?: string } }).data
636+
.nextPageToken;
623637
console.info(
624638
`[GetStorageInfo] Processed page, total files so far: ${totalFiles}, folders: ${totalFolders}, size: ${(totalSize / 1024 ** 4).toFixed(2)} TB`
625639
);

src/components/layout/Footer.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client";
22

3-
import { useState } from "react";
3+
import { useState, useEffect } from "react";
44

55
import { usePathname } from "next/navigation";
66

@@ -19,8 +19,13 @@ type Props = {
1919
export default function Footer({ content }: Props) {
2020
const pathname = usePathname();
2121
const loading = useLoading();
22-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
2322
const [loadTime, setLoadTime] = useState<number>(0);
23+
const [now, setNow] = useState<string | null>(null);
24+
25+
useEffect(() => {
26+
setNow(`${new Date().toISOString().slice(0, 19)}Z`);
27+
setLoadTime(performance.now());
28+
}, []);
2429

2530
if (NO_LAYOUT_PATHS.some((path) => new RegExp(path).test(pathname)))
2631
return null;
@@ -33,9 +38,9 @@ export default function Footer({ content }: Props) {
3338
<span>SYSTEM STATUS: OPERATIONAL</span>
3439
</div>
3540
<div className="text-muted-foreground/60"></div>
36-
<div className="text-xs font-mono text-muted-foreground">
37-
{new Date().toISOString().slice(0, 19)}Z
38-
</div>
41+
{now ? (
42+
<div className="text-xs font-mono text-muted-foreground">{now}</div>
43+
) : null}
3944
</div>
4045
{config.siteConfig.experimental_pageLoadTime &&
4146
(loading ? (

src/components/ui/form.tsx

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,33 +75,33 @@ const FormItemContext = React.createContext<FormItemContextValue>(
7575
{} as FormItemContextValue
7676
);
7777

78-
function FormItem({
79-
className,
80-
disableBorder,
81-
...props
82-
}: React.ComponentProps<"div"> & { disableBorder?: boolean }) {
78+
function FormItem(
79+
props: React.ComponentProps<"div"> & { disableBorder?: boolean }
80+
) {
81+
const { className, disableBorder, ...rest } = props;
82+
const _disableBorder = disableBorder;
8383
const id = React.useId();
8484

8585
return (
8686
<FormItemContext.Provider value={{ id }}>
8787
<div
8888
data-slot="form-item"
8989
className={cn("grid gap-2", className)}
90-
{...props}
90+
{...rest}
9191
/>
9292
</FormItemContext.Provider>
9393
);
9494
}
9595

96-
function FormLabel({
97-
className,
98-
resetDisabled,
99-
onFieldReset,
100-
...props
101-
}: React.ComponentProps<typeof LabelPrimitive.Root> & {
102-
resetDisabled?: boolean;
103-
onFieldReset?: () => void;
104-
}) {
96+
function FormLabel(
97+
props: React.ComponentProps<typeof LabelPrimitive.Root> & {
98+
resetDisabled?: boolean;
99+
onFieldReset?: () => void;
100+
}
101+
) {
102+
const { className, resetDisabled, onFieldReset, ...rest } = props;
103+
const _resetDisabled = resetDisabled;
104+
const _onFieldReset = onFieldReset;
105105
const { error, formItemId } = useFormField();
106106

107107
return (
@@ -110,7 +110,7 @@ function FormLabel({
110110
data-error={!!error}
111111
className={cn("data-[error=true]:text-destructive", className)}
112112
htmlFor={formItemId}
113-
{...props}
113+
{...rest}
114114
/>
115115
);
116116
}

0 commit comments

Comments
 (0)