diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..790e1105 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v20.10.0 diff --git a/bun.lockb b/bun.lockb index f8a40b94..4abc8b45 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/public/index.html b/index.html similarity index 56% rename from public/index.html rename to index.html index d6a36d67..4fba37ca 100644 --- a/public/index.html +++ b/index.html @@ -6,7 +6,7 @@ - + @@ -26,35 +26,13 @@ - - - + SUWIKI
- + diff --git a/package.json b/package.json index 3bd04404..503e97eb 100644 --- a/package.json +++ b/package.json @@ -2,63 +2,44 @@ "name": "suwiki", "version": "1.3.0", "private": true, - "proxy": "https://api.suwiki.kr", "dependencies": { - "@emotion/react": "^11.10.5", - "@emotion/styled": "^11.10.5", - "@mui/material": "^5.11.4", - "axios": "^1.2.2", + "@emotion/react": "^11.13.3", + "@emotion/styled": "^11.13.0", + "@mui/material": "^6.0.1", + "axios": "^1.7.5", "jwt-decode": "^3.1.2", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-error-boundary": "^4.0.4", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-error-boundary": "^4.0.13", "react-ga": "^3.3.1", - "react-hook-form": "^7.41.5", - "react-intersection-observer": "^9.4.1", - "react-query": "^3.39.2", - "react-router-dom": "^6.6.2", - "react-scripts": "5.0.1", + "react-hook-form": "^7.53.0", + "react-intersection-observer": "^9.13.0", + "react-query": "^3.39.3", + "react-router-dom": "^6.26.1", "react-star-ratings": "^2.3.0", - "recoil": "^0.7.6" + "recoil": "^0.7.7" }, "scripts": { - "start": "react-scripts start", - "build": "tsc && react-scripts build", - "test": "react-scripts test", - "eject": "react-scripts eject", + "dev": "vite", + "build": "vite build", "lint": "eslint", - "type:check": "tsc --noEmit" - }, - "eslintConfig": { - "extends": [ - "react-app", - "react-app/jest" - ] - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] + "compile": "tsc" }, "devDependencies": { - "@types/node": "^18.15.3", - "@types/react": "^18.0.28", - "@types/react-dom": "^18.0.11", - "@types/react-star-ratings": "^2.3.0", - "eslint": "^8.31.0", - "eslint-config-prettier": "^8.6.0", - "eslint-plugin-import": "^2.26.0", - "eslint-plugin-jsx-a11y": "^6.7.0", - "eslint-plugin-react": "^7.31.11", - "eslint-plugin-react-hooks": "^4.6.0", - "prettier": "^2.8.2", - "typescript": "^4.9.5" + "@types/node": "^18.19.47", + "@types/react": "^18.3.4", + "@types/react-dom": "^18.3.0", + "@types/react-star-ratings": "^2.3.3", + "@vitejs/plugin-react": "^4.3.1", + "eslint": "^8.57.0", + "eslint-config-prettier": "^8.10.0", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-jsx-a11y": "^6.9.0", + "eslint-plugin-prettier": "^5.2.1", + "eslint-plugin-react": "^7.35.0", + "eslint-plugin-react-hooks": "^4.6.2", + "prettier": "^2.8.8", + "typescript": "^4.9.5", + "vite": "^5.4.2" } } diff --git a/src/App.tsx b/src/App.tsx index 8a51fa6e..d1696951 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -20,7 +20,7 @@ import { Search, SignUp, } from 'pages'; -import RouteChangeTracker from 'RouteChangeTracker'; +import RouteChangeTracker from 'components/RouteChangeTracker'; const App = () => { return ( diff --git a/src/api/ApiController.ts b/src/api/ApiController.ts index 3bc39b76..e592de96 100644 --- a/src/api/ApiController.ts +++ b/src/api/ApiController.ts @@ -4,7 +4,8 @@ import jwtDecode, { type JwtPayload } from 'jwt-decode'; import { useRecoilState } from 'recoil'; import { isLoginStorage } from 'utils/loginStorage'; import { logout, refresh } from './etc'; -const PROXY_URL = window.location.hostname === 'localhost' ? '' : '/proxy'; + +const PROXY_URL = '/api'; axios.defaults.withCredentials = true; const JwtInterceptors = () => { diff --git a/src/api/User.ts b/src/api/User.ts index e2bc6549..7c0b9a0a 100644 --- a/src/api/User.ts +++ b/src/api/User.ts @@ -12,7 +12,7 @@ import type { RestrictionInfo, UserProfileInfo, } from 'types/user'; -import { queryClient } from '../index'; +import { queryClient } from '../main'; import JwtInterceptors from './ApiController'; import { Review } from 'types/evaluate'; import { MyExam } from 'types/exam'; diff --git a/src/components/AsyncBoundary.tsx b/src/components/AsyncBoundary.tsx deleted file mode 100644 index a351f3e5..00000000 --- a/src/components/AsyncBoundary.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { PropsWithChildren, Suspense, type ComponentProps } from 'react'; -import { ErrorBoundary, type FallbackProps } from 'react-error-boundary'; - -type ErrorBoundaryProps = ComponentProps; - -interface AsyncBoundaryProps extends Omit { - pendingFallback: ComponentProps['fallback']; - rejectedFallback: ErrorBoundaryProps['fallbackRender']; -} - -const Substitute = ({ error }: FallbackProps) => { - return <>{error.message}; -}; - -const AsyncBoundary = ({ - pendingFallback, - rejectedFallback, - children, -}: PropsWithChildren) => { - return ( - - {children} - - ); -}; - -export default AsyncBoundary; diff --git a/src/components/Lecture/LectureContainer.tsx b/src/components/Lecture/LectureContainer.tsx index 2f6c053a..48889e13 100644 --- a/src/components/Lecture/LectureContainer.tsx +++ b/src/components/Lecture/LectureContainer.tsx @@ -3,24 +3,24 @@ import { FlexWrap } from 'styles/common'; import { LectureCard } from 'components'; import type { LectureDetailItem } from 'types/lecture'; -const LectureContainer = ({ data }: { data: LectureDetailItem[] }) => { - const oddList = data.filter((row, i) => !(i % 2) && row); - const evenList = data.filter((row, i) => i % 2 && row); +const LectureContainer = ({ data }: { data?: LectureDetailItem[] }) => { + const oddList = data?.filter((row, i) => !(i % 2) && row); + const evenList = data?.filter((row, i) => i % 2 && row); return ( - {oddList.map((row) => ( + {oddList?.map((row) => ( ))} - {evenList.map((row) => ( + {evenList?.map((row) => ( ))} - {data.map((row) => ( + {data?.map((row) => ( ))} diff --git a/src/components/List/LectureList.tsx b/src/components/List/LectureList.tsx index 52430c2b..ef9cc3f2 100644 --- a/src/components/List/LectureList.tsx +++ b/src/components/List/LectureList.tsx @@ -2,19 +2,29 @@ import { LectureContainer } from 'components'; import { fakeLectureList } from 'constants/placeholderData'; import useLectureQuery from 'hooks/useLectureQuery'; import { FlexWrap } from 'styles/common'; +import { MainLecture } from 'types/lecture'; interface LectureListProps { + pages: + | ( + | { + data: MainLecture; + isLast: boolean; + nextPage: number; + } + | undefined + )[] + | undefined; count: number; - data: any[]; } -const LectureList = ({ count, data }: LectureListProps) => { +const LectureList = ({ count, pages }: LectureListProps) => { const { Search } = useLectureQuery(); const { nextLoading, value, ref } = Search(); return count ? ( <> - {data.map((page) => ( + {pages?.map((page) => ( ))}
diff --git a/src/components/Major/MajorSearch.tsx b/src/components/Major/MajorSearch.tsx index 8ea13e9c..ca67c983 100644 --- a/src/components/Major/MajorSearch.tsx +++ b/src/components/Major/MajorSearch.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled/macro'; +import styled from '@emotion/styled'; import * as styles from '@mui/material/styles'; import { Fragment, useState } from 'react'; import { TextField } from '@mui/material'; diff --git a/src/RouteChangeTracker.ts b/src/components/RouteChangeTracker.ts similarity index 100% rename from src/RouteChangeTracker.ts rename to src/components/RouteChangeTracker.ts diff --git a/src/components/Write/WriteEvaluation.tsx b/src/components/Write/WriteEvaluation.tsx index 2287024f..1c21bfa9 100644 --- a/src/components/Write/WriteEvaluation.tsx +++ b/src/components/Write/WriteEvaluation.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled/macro'; +import styled from '@emotion/styled'; import { Fragment } from 'react'; import SemesterSelect from 'components/SemesterSelect'; import { diff --git a/src/components/Write/WriteTestInfo.tsx b/src/components/Write/WriteTestInfo.tsx index e3e4bfba..b11b1fc7 100644 --- a/src/components/Write/WriteTestInfo.tsx +++ b/src/components/Write/WriteTestInfo.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled/macro'; +import styled from '@emotion/styled'; import { useState } from 'react'; import { useMutation } from 'react-query'; import { User } from 'api'; diff --git a/src/index.tsx b/src/main.tsx similarity index 71% rename from src/index.tsx rename to src/main.tsx index 0848a72f..e66247d5 100644 --- a/src/index.tsx +++ b/src/main.tsx @@ -1,9 +1,7 @@ import './styles/globalStyle.css'; import axios from 'axios'; -import AsyncBoundary from 'components/AsyncBoundary'; import { CACHE_TIME } from 'constants/cacheTime'; -import { BadGateway } from 'pages'; import React from 'react'; import ReactDOM from 'react-dom/client'; import { initialize } from 'react-ga'; @@ -29,13 +27,11 @@ axios.defaults.withCredentials = true; ReactDOM.createRoot(document.getElementById('root')!).render( - } rejectedFallback={() => }> - - - - - - - + + + + + + ); diff --git a/src/pages/Search.tsx b/src/pages/Search.tsx index 07452d7c..f30c0478 100644 --- a/src/pages/Search.tsx +++ b/src/pages/Search.tsx @@ -1,6 +1,6 @@ import styled from '@emotion/styled'; import { LectureList, LectureSearch, MajorSelect, OptionSelect } from 'components'; -import { fakeLectureList, sortOptions } from 'constants/placeholderData'; +import { sortOptions } from 'constants/placeholderData'; import useLectureQuery from 'hooks/useLectureQuery'; const Search = () => { @@ -29,7 +29,7 @@ const Search = () => { - +
diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 00000000..11f02fe2 --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/tsconfig.json b/tsconfig.json index bfee612b..82df0a73 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,6 +16,18 @@ "noEmit": true, "jsx": "react-jsx", "baseUrl": "src", + "paths": { + "*": ["*"], + "api/*": ["api/*"], + "app/*": ["app/*"], + "constants/*": ["constants/*"], + "components/*": ["components/*"], + "hooks/*": ["hooks/*"], + "pages/*": ["pages/*"], + "styles/*": ["styles/*"], + "types/*": ["types/*"], + "utils/*": ["utils/*"] + }, "noUnusedLocals": true, "noUnusedParameters": true, diff --git a/vite.config.mts b/vite.config.mts new file mode 100644 index 00000000..41788f87 --- /dev/null +++ b/vite.config.mts @@ -0,0 +1,30 @@ +import react from '@vitejs/plugin-react'; +import { defineConfig } from 'vite'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + server: { + port: 3000, + proxy: { + '/api': { + target: 'https://api.suwiki.kr', + changeOrigin: true, + rewrite: (path) => path.replace(/^\/api/, ''), + }, + }, + }, + resolve: { + alias: { + api: '/src/api', + app: '/src/app', + constants: '/src/constants', + components: '/src/components', + hooks: '/src/hooks', + pages: '/src/pages', + styles: '/src/styles', + types: '/src/types', + utils: '/src/utils', + }, + }, +});