Skip to content

Commit

Permalink
feat(init): init project
Browse files Browse the repository at this point in the history
  • Loading branch information
anhkhoa1408 committed Aug 3, 2024
0 parents commit 5968528
Show file tree
Hide file tree
Showing 27 changed files with 3,879 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules
.DS_Store
dist
dist-ssr
*.local
node_modules/*
yarn.lock
45 changes: 45 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 2020,
sourceType: 'module',
ecmaFeatures: {
jsx: true,
},
},
settings: {
react: {
version: 'detect',
},
},
env: {
browser: true,
amd: true,
node: true,
},
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:jsx-a11y/recommended',
'plugin:prettier/recommended', // Make sure this is always the last element in the array.
],
plugins: ['simple-import-sort', 'prettier'],
rules: {
'prettier/prettier': ['error', {}, { usePrettierrc: true }],
'react/react-in-jsx-scope': 'off',
'jsx-a11y/accessible-emoji': 'off',
'react/prop-types': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error',
'jsx-a11y/anchor-is-valid': [
'error',
{
components: ['Link'],
specialLink: ['hrefLeft', 'hrefRight'],
aspects: ['invalidHref', 'preferButton'],
},
],
},
}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/node_modules
7 changes: 7 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules
.DS_Store
dist
dist-ssr
*.local
node_modules/*
yarn.lock
29 changes: 29 additions & 0 deletions .prettierrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module.exports = {
semi: false,
trailingComma: 'all',
singleQuote: true,
printWidth: 80,
tabWidth: 2,
jsxBracketSameLine: true,
endOfLine: 'auto',
}

// {
// "arrowParens": "always",
// "bracketSpacing": true,
// "embeddedLanguageFormatting": "auto",
// "htmlWhitespaceSensitivity": "css",
// "insertPragma": false,
// "jsxBracketSameLine": false,
// "jsxSingleQuote": false,
// "proseWrap": "preserve",
// "quoteProps": "as-needed",
// "requirePragma": false,
// "semi": true,
// "singleQuote": false,
// "tabWidth": 2,
// "trailingComma": "es5",
// "useTabs": false,
// "vueIndentScriptAndStyle": false,
// "printWidth": 100
// }
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Vite + React + RTK Query

This project is used for configuring and learning RTK Query with axios
1 change: 1 addition & 0 deletions config/CSSStub.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = {}
13 changes: 13 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="src/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
40 changes: 40 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"name": "demo-rtk-query",
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"serve": "vite preview",
"type-check": "tsc",
"test": "vitest",
"lint": "eslint --fix --ext .js,.jsx,.ts,.tsx ."
},
"dependencies": {
"@reduxjs/toolkit": "^2.2.7",
"axios": "^1.7.3",
"query-string": "^9.1.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-redux": "^8.0.2",
"redux-persist": "^6.0.0"
},
"devDependencies": {
"@testing-library/react": "^12.1.4",
"@typescript-eslint/eslint-plugin": "^5.16.0",
"@typescript-eslint/parser": "^5.16.0",
"@vitejs/plugin-react": "^1.2.0",
"eslint": "^8.12.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-react": "^7.29.4",
"eslint-plugin-simple-import-sort": "^7.0.0",
"jsdom": "^19.0.0",
"prettier": "^2.6.1",
"typescript": "^4.6.3",
"vite": "^2.8.6",
"vitest": "^0.7.11"
},
"license": "MIT"
}
75 changes: 75 additions & 0 deletions src/App.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
:root {
--primay: black;
--bg-primay: white;

--link: #2a0b0b;
}

.App {
text-align: center;
}

.App-logo {
height: 40vmin;
pointer-events: none;
}

p {
margin: 20px 0px;
}

.header {
font-size: 3rem;
}

.body {
margin: 20px 0 10px;
font-size: 0.9rem;
}

button {
outline: none;
border: none;
border-radius: 8px;
padding: 10px 35px;

background: #845ec2;
color: white;
}

@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}

.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);

background: var(--bg-primay);
color: var(--primay);
}

.App-link {
color: #61dafb;
color: var(--link);
}

@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

button {
font-size: calc(10px + 2vmin);
}
22 changes: 22 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import './App.css'

import React from 'react'
import { Provider } from 'react-redux'
import { PersistGate } from 'redux-persist/integration/react'

import { persistor, store } from './state/store'
import Container from './views/Container'

function App() {
return (
<Provider store={store}>
<PersistGate persistor={persistor}>
<div className="App" data-testid="app-page">
<Container />
</div>
</PersistGate>
</Provider>
)
}

export default App
17 changes: 17 additions & 0 deletions src/__tests__/App.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { render, screen } from '@testing-library/react'
import React from 'react'
import { describe, expect, it } from 'vitest'

import App from '../App'

/**
* @vitest-environment jsdom
*/

describe('App page', () => {
it('renders page', () => {
render(<App />)

expect(screen.getByTestId('app-page')).toBeTruthy()
})
})
32 changes: 32 additions & 0 deletions src/api/axiosBaseQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import type { BaseQueryFn } from '@reduxjs/toolkit/query'
import type { AxiosError, AxiosRequestConfig } from 'axios'

import axiosClient from './axiosClient'

const axiosBaseQuery =
(): BaseQueryFn<
{
url: string
method?: AxiosRequestConfig['method']
data?: AxiosRequestConfig['data']
params?: AxiosRequestConfig['params']
},
unknown,
unknown
> =>
async (request) => {
try {
const result = await axiosClient.request(request)
return { data: result.data }
} catch (axiosError) {
const err = axiosError as AxiosError
return {
error: {
status: err.response?.status,
data: err.response?.data || err.message,
},
}
}
}

export default axiosBaseQuery
41 changes: 41 additions & 0 deletions src/api/axiosClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import axios from 'axios'
import queryString from 'query-string'

import { store } from '../state/store'

const axiosClient = axios.create({
baseURL: 'https://dummyjson.com/products',
headers: {
'content-type': 'application/json',
},
paramsSerializer: {
serialize: (params) => {
return queryString.stringify(params, {
skipEmptyString: true,
skipNull: true,
})
},
},
timeout: 15000,
})

axiosClient.interceptors.request.use(async (config) => {
const token = store.getState().auth.token
if (token) config.headers.set('Authorization', `Bearer ${token}`)
return config
})

axiosClient.interceptors.response.use(
(response) => {
try {
return response
} catch (error) {
return response
}
},
(error) => {
throw error
},
)

export default axiosClient
20 changes: 20 additions & 0 deletions src/api/productApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { createApi } from '@reduxjs/toolkit/query/react'

import axiosBaseQuery from './axiosBaseQuery'

export const productApi = createApi({
reducerPath: 'productApi',
baseQuery: axiosBaseQuery(),
endpoints(build) {
return {
getAllProducts: build.query({
query: () => ({ url: '', method: 'get' }),
}),
getProductById: build.query({
query: (id: string) => ({ url: `/${id}`, method: 'get' }),
}),
}
},
})

export const { useGetAllProductsQuery, useGetProductByIdQuery } = productApi
1 change: 1 addition & 0 deletions src/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions src/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',
'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
}
1 change: 1 addition & 0 deletions src/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 5968528

Please sign in to comment.