Skip to content

feat: refactor, typed enhacement #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 18 additions & 15 deletions frontend/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -1,36 +1,39 @@
module.exports = {
root: true,
env: { browser: true, es2020: true, node: true },
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-type-checked',
'plugin:react-hooks/recommended',
'plugin:react/jsx-runtime',
'plugin:prettier/recommended',
'plugin:react-query/recommended',
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
ignorePatterns: ['dist', '.eslintrc.cjs'], // Ignore output and config files
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features
sourceType: 'module', // Allows for the use of imports
ecmaVersion: 'latest', // Parse latest ECMAScript features
sourceType: 'module', // Enable import/export syntax
ecmaFeatures: {
jsx: true, // Allows for the parsing of JSX,
jsx: true, // Enable JSX syntax parsing
},
project: ['./tsconfig.json', './vite.config.ts'], // Use TypeScript project settings for type checking
tsconfigRootDir: __dirname, // Set the root directory for TypeScript config files relative to this file
},
plugins: ['react-refresh', 'prettier', 'react-query'],
rules: {
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
{ allowConstantExport: true }, // Warn when non-component exports are found
],
'no-use-before-define': 'off',
semi: ['error', 'always'],
'@typescript-eslint/ban-ts-ignore': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'react/no-unescaped-entities': 'off',
'react/react-in-jsx-scope': 'off',
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
'no-use-before-define': 'off', // TypeScript handles this rule well
semi: ['error', 'always'], // Enforce semicolons at the end of statements
'@typescript-eslint/ban-ts-ignore': 'off', // Allow @ts-ignore (use cautiously)
'@typescript-eslint/no-explicit-any': 'off', // Allow 'any' type (can be tightened later)
'react/no-unescaped-entities': 'off', // Allow unescaped characters in JSX (like `&`)
'react-hooks/rules-of-hooks': 'error', // Enforce React Hooks rules
'react-hooks/exhaustive-deps': 'warn', // Warn about missing dependencies in hooks
'@typescript-eslint/no-unsafe-argument': 'warn',
},
};
113 changes: 113 additions & 0 deletions frontend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,116 @@ If you are developing a production application, we recommend updating the config
- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list

## TypeScript Configuration Documentation

1. Main TypeScript Configuration (tsconfig.json)

```json
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"jsx": "react-jsx",
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"isolatedModules": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"resolveJsonModule": true,
"allowImportingTsExtensions": true,
"noEmit": true,
"types": ["vite/client"],
"typeRoots": ["./@types", "./node_modules/@types"]
}
```

## Explanation of compilerOptions

- **target: "ESNext":** Set the JavaScript language version for the output code to the latest ECMAScript features.
- **module: "ESNext":** Use the latest ECMAScript module features like import and export.
- **moduleResolution: "bundler":** Tells TypeScript how to resolve modules, optimized for bundlers like Vite.
- **jsx: "react-jsx":** Enable the React 17 JSX transform without needing to import React in each JSX file.
- **strict: true:** Enables strict type-checking settings for better type safety.
- **noImplicitAny: true:** Prevents variables from being implicitly typed as any.
- **strictNullChecks: true:** Makes null and undefined distinct types, improving type safety.
- **noUnusedLocals: true:** Flags unused local variables as errors.
- **noUnusedParameters: true:** Flags unused parameters in functions as errors.
- **noFallthroughCasesInSwitch: true:** Prevents fall-through cases in switch statements.
- **forceConsistentCasingInFileNames:** true: Enforces consistent casing for file names, helping avoid issues across different file systems.
- **isolatedModules: true:** Ensures that TypeScript files can be transpiled independently, which is useful for bundling tools.
- **allowSyntheticDefaultImports: true:** Allows default imports from non-default-exporting modules.
- **esModuleInterop: true:** Allows compatibility with CommonJS-style modules.
- **lib: ["ESNext", "DOM", "DOM.Iterable"]:** Specifies the libraries to include during compilation, ensuring support for the latest JavaScript and DOM features.
- **resolveJsonModule: true:** Allows importing JSON files as modules.
- **allowImportingTsExtensions: true:** Enables importing TypeScript files with .ts and .tsx extensions.
- **noEmit: true:** Prevents TypeScript from emitting JavaScript files during compilation, useful when using a bundler.
- **types: ["vite/client"]:** Specifies types related to Vite’s client-side environment for better type checking.
- **typeRoots: ["./@types", "./node_modules/@types"]:** Defines directories where TypeScript should look for type declarations.

## Includes and Excludes

```json
"include": ["src/**/*.ts", "src/**/*.tsx", "./vite.config.ts"],,
"exclude": ["node_modules", "dist"]
```

- **include:** Specifies the files to include in the compilation process, such as all .ts and .tsx files inside the src directory.
- **exclude:** Excludes certain directories (e.g., node_modules, dist) from being compiled by TypeScript.

## Extending Other Configurations

```json
"extends": "./tsconfig.paths.json",
"references": []
```

- **extends:** This allows tsconfig.json to inherit settings from tsconfig.paths.json, which handles path alias configurations.
- **references:** In a multi-project setup, this field is used to reference other TypeScript projects. It is left empty here since it's not needed.

2. Path Aliases (tsconfig.paths.json)

```json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}
```

## Path Aliases Explanation

- **baseUrl:** Defines the base directory for resolving non-relative module names. By setting it to ".", we specify that the root directory of the project is the base directory.
- **paths:** This configures path aliases to simplify imports. For example, "@/_": ["./src/_"] allows importing files from the src directory using the @ alias:

3. Test Configuration (tsconfig.test.json)

```json
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"types": ["vitest/globals", "vitest", "@testing-library/jest-dom"],
"noUnusedLocals": false,
"noUnusedParameters": false
}
}
```

## Test Configuration Explanation

- **extends:** Inherits from tsconfig.base.json, so the settings from the base configuration are shared across all configurations.
- **types:** Specifies additional type definitions for testing. This includes types for Vitest and Jest DOM, which are commonly used in testing React components:
- **vitest/globals:** Global types for Vitest.
- **vitest:** Types for Vitest itself.
- **@testing-library/jest-dom:** Types for testing React components with Jest DOM.
- **noUnusedLocals and noUnusedParameters:** These are set to false during testing to allow temporary or incomplete code while writing tests, where unused variables and parameters might be present.
25 changes: 6 additions & 19 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fullstack_tasks-frontend",
"version": "1.2.0",
"version": "1.3.0",
"description": "",
"type": "module",
"scripts": {
Expand All @@ -27,10 +27,9 @@
"@fortawesome/react-fontawesome": "^0.2.2",
"@fvilers/disable-react-devtools": "^1.3.0",
"@tanstack/react-query": "^5.51.23",
"axios": "^1.7.5",
"axios": "^1.7.7",
"date-fns": "^2.30.0",
"dompurify": "^3.1.7",
"dotenv": "^16.4.5",
"formik": "^2.4.6",
"i18next": "^23.12.2",
"react": "^18.3.1",
Expand Down
12 changes: 6 additions & 6 deletions frontend/src/api/auth.api.ts → frontend/src/api/AuthApi.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { RegisterType } from '@/features/auth/types/register.type';
import { protectedRequest, publicRequest } from '@/lib/axios';
import { LoginType } from '@/features/auth/types/login.type';
import { ResetPasswordType } from '@/features/auth/types/reset-password.type';
import { ApiBaseResponse } from '@/types/api-base.type';
import { RegisterType } from '@/types/RegisterType';
import { protectedRequest, publicRequest } from '@/lib/axios/Axios';
import { LoginType } from '@/types/LoginType';
import { ResetPasswordType } from '@/types/ResetPasswordType';
import { ApiBaseResponse } from '@/types/ApiBaseType';
import {
ForgotPasswordResponse,
ForgotPasswordType,
} from '@/features/auth/types/forgot-password.type';
} from '@/types/ForgotPasswordType';

export const API_REFRESH_TOKEN = async () => {
return await protectedRequest<null, ApiBaseResponse>({
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/api/task.api.ts → frontend/src/api/TaskApi.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { protectedRequest } from '@/lib/axios';
import { protectedRequest } from '@/lib/axios/Axios';
import {
TaskDeleteResponse,
TaskResponse,
Expand All @@ -7,7 +7,7 @@ import {
UpdateCompletedTaskType,
UpdateImportantTaskType,
UpdateTaskType,
} from '@/features/tasks/types/task.type';
} from '@/types/TaskType';

export const API_TASK_UPDATE = async (data: UpdateTaskType) => {
return await protectedRequest<
Expand Down
14 changes: 7 additions & 7 deletions frontend/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import '@/lib/i18n';
import AppProvider from '@/providers/app-provider';
import AppRoute from '@/routes';
import AuthProvider from '@/providers/auth-provider';
import { queryClient } from '@/lib/react-query';
import '@/lib/i18n/i18n';
import AppProvider from '@/contexts/app-context/AppProvider';
import AppRoutes from '@/routes/Routes';
import { queryClient } from '@/lib/react-query/ReactQuery';
import { Toaster } from 'react-hot-toast';
import { QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import useDisableReactDevTools from '@/hooks/useDisableReactDevTools';
import useDisableReactDevTools from '@/hooks/use-disable-react-dev-tools/useDisableReactDevTools';
import AuthProvider from '@/contexts/auth-context/AuthProvider';

const App = () => {
// Disable React DevTools in production
Expand All @@ -17,7 +17,7 @@ const App = () => {
<Toaster position="bottom-left" />
<AuthProvider>
<AppProvider>
<AppRoute />
<AppRoutes />
</AppProvider>
</AuthProvider>
{/* React Query DevTools for debugging */}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,18 @@ const IconButton = ({
}: IconButtonProps) => {
const { t } = useTranslation();

const handleButtonClick = () => {
if (!isDisabled && !isLoading && handleClick) {
handleClick();
}
};

return (
<button
type={type}
title={title && t(title)}
disabled={isDisabled}
onClick={handleClick}
disabled={isDisabled || isLoading}
onClick={handleButtonClick}
className={`font-medium text-sm p-2.5 text-center inline-flex items-center
mr-2 text-blue-500 hover:text-white rounded-full hover:bg-blue-500 ${
isDisabled || isLoading ? 'cursor-not-allowed' : ''
Expand Down
Loading
Loading