- Removed direct imports of DashboardLayout from various portal pages to enforce the use of shared layout components. - Introduced ESLint rules to prevent importing DashboardLayout directly in (portal) pages, encouraging the use of the shared route-group layout. - Updated navigation methods to utilize Next.js router instead of window.location for improved routing consistency. - Enhanced loading states and error handling across multiple pages for better user experience.
177 lines
5.0 KiB
JavaScript
177 lines
5.0 KiB
JavaScript
/* eslint-env node */
|
|
import process from "node:process";
|
|
import js from "@eslint/js";
|
|
import tseslint from "typescript-eslint";
|
|
import prettier from "eslint-plugin-prettier";
|
|
import { FlatCompat } from "@eslint/eslintrc";
|
|
import path from "node:path";
|
|
import globals from "globals";
|
|
|
|
// Use FlatCompat to consume Next.js' legacy shareable configs under apps/portal
|
|
const compat = new FlatCompat({ baseDirectory: path.resolve("apps/portal") });
|
|
|
|
export default [
|
|
// Global ignores
|
|
{
|
|
ignores: [
|
|
"**/node_modules/**",
|
|
"**/dist/**",
|
|
"**/.next/**",
|
|
"**/build/**",
|
|
"**/coverage/**",
|
|
"**/next-env.d.ts",
|
|
],
|
|
},
|
|
|
|
// Base JS recommendations for all files
|
|
js.configs.recommended,
|
|
|
|
// Prettier integration (warn-only)
|
|
{
|
|
plugins: { prettier },
|
|
rules: {
|
|
"prettier/prettier": "warn",
|
|
},
|
|
},
|
|
|
|
// TypeScript (type-checked) for TS files only
|
|
...tseslint.configs.recommendedTypeChecked.map(config => ({
|
|
...config,
|
|
files: ["**/*.ts", "**/*.tsx"],
|
|
languageOptions: {
|
|
...(config.languageOptions || {}),
|
|
globals: {
|
|
...globals.node,
|
|
},
|
|
},
|
|
})),
|
|
{
|
|
files: ["apps/bff/**/*.ts", "packages/shared/**/*.ts"],
|
|
languageOptions: {
|
|
parserOptions: {
|
|
// Enable project service for monorepos without per-invocation project config
|
|
projectService: true,
|
|
tsconfigRootDir: process.cwd(),
|
|
},
|
|
},
|
|
rules: {
|
|
"@typescript-eslint/consistent-type-imports": "error",
|
|
"@typescript-eslint/no-unused-vars": [
|
|
"warn",
|
|
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
|
|
],
|
|
"no-console": ["warn", { allow: ["warn", "error"] }],
|
|
},
|
|
},
|
|
|
|
// Enforce consistent strict rules across shared as well
|
|
{
|
|
files: ["packages/shared/**/*.ts"],
|
|
rules: {
|
|
"@typescript-eslint/no-redundant-type-constituents": "error",
|
|
"@typescript-eslint/no-explicit-any": "error",
|
|
"@typescript-eslint/no-unsafe-return": "error",
|
|
"@typescript-eslint/no-unsafe-call": "error",
|
|
"@typescript-eslint/no-unsafe-member-access": "error",
|
|
},
|
|
},
|
|
|
|
// Next.js app: apply Next's recommended config; TS rules only on TS files
|
|
...compat
|
|
.extends("next/core-web-vitals")
|
|
.map(config => ({ ...config, files: ["apps/portal/**/*.{js,jsx,ts,tsx}"] })),
|
|
...compat
|
|
.extends("next/typescript")
|
|
.map(config => ({ ...config, files: ["apps/portal/**/*.{ts,tsx}"] })),
|
|
|
|
// Ensure type-aware rules in portal have parser services
|
|
{
|
|
files: ["apps/portal/**/*.{ts,tsx}"],
|
|
languageOptions: {
|
|
parserOptions: {
|
|
projectService: true,
|
|
tsconfigRootDir: process.cwd(),
|
|
},
|
|
},
|
|
rules: {
|
|
// App Router: disable pages-directory specific rule
|
|
"@next/next/no-html-link-for-pages": "off",
|
|
},
|
|
},
|
|
|
|
// Prevent importing the DashboardLayout directly in (portal) pages.
|
|
// Pages should rely on the shared route-group layout at (portal)/layout.tsx.
|
|
{
|
|
files: ["apps/portal/src/app/(portal)/**/*.{ts,tsx}"],
|
|
rules: {
|
|
"no-restricted-imports": [
|
|
"error",
|
|
{
|
|
patterns: [
|
|
{
|
|
group: ["@/components/layout/dashboard-layout"],
|
|
message:
|
|
"Use the shared (portal)/layout.tsx instead of importing DashboardLayout in pages.",
|
|
},
|
|
],
|
|
},
|
|
],
|
|
// Prefer Next.js <Link> and router, forbid window/location hard reload in portal pages
|
|
"no-restricted-syntax": [
|
|
"error",
|
|
{
|
|
selector:
|
|
"MemberExpression[object.name='window'][property.name='location']",
|
|
message:
|
|
"Use next/link or useRouter for navigation, not window.location.",
|
|
},
|
|
{
|
|
selector:
|
|
"MemberExpression[object.name='location'][property.name=/^(href|assign|replace)$/]",
|
|
message:
|
|
"Use next/link or useRouter for navigation, not location.*.",
|
|
},
|
|
],
|
|
},
|
|
},
|
|
// Allow the shared layout file itself to import the layout component
|
|
{
|
|
files: ["apps/portal/src/app/(portal)/layout.tsx"],
|
|
rules: {
|
|
"no-restricted-imports": "off",
|
|
},
|
|
},
|
|
// Allow controlled window.location usage for invoice SSO download
|
|
{
|
|
files: ["apps/portal/src/app/(portal)/billing/invoices/[id]/page.tsx"],
|
|
rules: {
|
|
"no-restricted-syntax": "off",
|
|
},
|
|
},
|
|
|
|
// Node globals for Next config file
|
|
{
|
|
files: ["apps/portal/next.config.mjs"],
|
|
languageOptions: {
|
|
globals: {
|
|
...globals.node,
|
|
},
|
|
},
|
|
},
|
|
|
|
// BFF: strict rules enforced
|
|
{
|
|
files: ["apps/bff/**/*.ts"],
|
|
rules: {
|
|
"@typescript-eslint/no-explicit-any": "error",
|
|
"@typescript-eslint/no-unsafe-assignment": "error",
|
|
"@typescript-eslint/no-unsafe-member-access": "error",
|
|
"@typescript-eslint/no-unsafe-call": "error",
|
|
"@typescript-eslint/no-unsafe-return": "error",
|
|
"@typescript-eslint/no-unsafe-argument": "error",
|
|
"@typescript-eslint/require-await": "error",
|
|
"@typescript-eslint/no-floating-promises": "error",
|
|
},
|
|
},
|
|
];
|