├── public ├── _redirects ├── favicon.ico └── index.html ├── src ├── react-app-env.d.ts ├── constants │ ├── units.constants.ts │ ├── token.contant.ts │ └── query.constant.ts ├── repositories │ ├── profiles │ │ ├── profileRepository.param.ts │ │ └── profileRepository.ts │ ├── tags │ │ └── tagsRepository.ts │ ├── users │ │ ├── usersRepository.param.ts │ │ └── usersRepository.ts │ ├── articles │ │ ├── articlesRepository.param.ts │ │ └── articlesRepository.ts │ └── apiClient.ts ├── lib │ ├── utils │ │ ├── scrollToTop.ts │ │ ├── generateOneToNArray.ts │ │ └── convertToDate.ts │ ├── token.ts │ ├── hooks │ │ ├── useIsLoginContext.tsx │ │ └── useInputs.tsx │ └── routerMeta.ts ├── pages │ ├── NotFoundPage.tsx │ ├── SettingPage.tsx │ ├── ProfilePage.tsx │ ├── HomePage.tsx │ ├── SignInPage.tsx │ ├── SignUpPage.tsx │ ├── ArticlePage.tsx │ ├── NewArticlePage.tsx │ └── EditArticlePage.tsx ├── components │ ├── LoadingFallback.tsx │ ├── common │ │ ├── Layout.tsx │ │ └── Footer.tsx │ ├── header │ │ ├── NavItem.tsx │ │ ├── ProfileItem.tsx │ │ └── Header.tsx │ ├── article │ │ ├── ButtonSelector.tsx │ │ ├── ButtonsWIthAccess.tsx │ │ ├── ButtonsWIthoutAccess.tsx │ │ └── Comment.tsx │ ├── HOC │ │ └── ProtectedRoute.tsx │ ├── ErrorFallback.tsx │ ├── Profile.tsx │ ├── feed │ │ ├── FeedList.tsx │ │ └── Feed.tsx │ ├── profile │ │ └── FollowButton.tsx │ └── SettingForm.tsx ├── queries │ ├── queryClient.ts │ ├── user.query.ts │ ├── profiles.query.ts │ └── articles.query.ts ├── App.tsx ├── contexts │ └── UserContextProvider.tsx ├── interfaces │ └── main.d.ts ├── index.tsx └── Router.tsx ├── .eslintignore ├── tsconfig.paths.json ├── babel.config.js ├── .prettierrc ├── craco.config.js ├── .gitignore ├── __tests__ └── UnitsTest.ts ├── tsconfig.json ├── .eslintrc.json ├── package.json └── README.md /public/_redirects: -------------------------------------------------------------------------------- 1 | /* /index.html 200 -------------------------------------------------------------------------------- /src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src/constants/units.constants.ts: -------------------------------------------------------------------------------- 1 | export const UNIT_PER_PAGE = 10; 2 | -------------------------------------------------------------------------------- /src/constants/token.contant.ts: -------------------------------------------------------------------------------- 1 | export const ACCESS_TOKEN_KEY = 'jwtToken'; 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /craco.config.js 3 | /__tests__ 4 | /babel.config.js 5 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiheon788/react-query-realworld/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/repositories/profiles/profileRepository.param.ts: -------------------------------------------------------------------------------- 1 | export interface profileParam { 2 | username: string; 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/utils/scrollToTop.ts: -------------------------------------------------------------------------------- 1 | const scrollToTop = () => { 2 | window.scrollTo(0, 0); 3 | }; 4 | 5 | export default scrollToTop; 6 | -------------------------------------------------------------------------------- /tsconfig.paths.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./src", 4 | "paths": { 5 | "@/*": ["*"] 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | ['@babel/preset-env', {targets: {node: 'current'}}], 4 | '@babel/preset-typescript', 5 | ], 6 | }; -------------------------------------------------------------------------------- /src/lib/utils/generateOneToNArray.ts: -------------------------------------------------------------------------------- 1 | const generateOneToNArray = (length: number) => { 2 | return Array.from({ length }, (_, i) => i + 1); 3 | }; 4 | 5 | export default generateOneToNArray; 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "semi": true, 4 | "useTabs": false, 5 | "tabWidth": 2, 6 | "trailingComma": "all", 7 | "printWidth": 120, 8 | "parser": "typescript", 9 | "endOfLine": "auto" 10 | } -------------------------------------------------------------------------------- /src/repositories/tags/tagsRepository.ts: -------------------------------------------------------------------------------- 1 | import apiClient from '@/repositories/apiClient'; 2 | 3 | export const getTags = async () => { 4 | return await apiClient({ 5 | method: 'get', 6 | url: `/tags`, 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /src/pages/NotFoundPage.tsx: -------------------------------------------------------------------------------- 1 | const NotFoundPage = () => { 2 | return ( 3 |
4 |

Not Found Page

5 |
6 | ); 7 | }; 8 | 9 | export default NotFoundPage; 10 | -------------------------------------------------------------------------------- /src/components/LoadingFallback.tsx: -------------------------------------------------------------------------------- 1 | const LoadingFallback = () => { 2 | return ( 3 |
4 |

Loading...

5 |
6 | ); 7 | }; 8 | 9 | export default LoadingFallback; 10 | -------------------------------------------------------------------------------- /src/queries/queryClient.ts: -------------------------------------------------------------------------------- 1 | import { QueryClient } from '@tanstack/react-query'; 2 | const queryClient = new QueryClient({ 3 | defaultOptions: { 4 | queries: { 5 | suspense: true, 6 | retry: false, 7 | }, 8 | }, 9 | }); 10 | 11 | export default queryClient; 12 | -------------------------------------------------------------------------------- /src/constants/query.constant.ts: -------------------------------------------------------------------------------- 1 | export const QUERY_USER_KEY = 'user'; 2 | export const QUERY_ARTICLES_KEY = 'articles'; 3 | export const QUERY_ARTICLE_KEY = 'article'; 4 | export const QUERY_COMMENTS_KEY = 'comments'; 5 | export const QUERY_PROFILE_KEY = 'profile'; 6 | export const QUERY_TAG_KEY = 'tags'; 7 | -------------------------------------------------------------------------------- /src/lib/token.ts: -------------------------------------------------------------------------------- 1 | class Token { 2 | public getToken(key: string) { 3 | return localStorage.getItem(key); 4 | } 5 | 6 | public setToken(key: string, token: string) { 7 | localStorage.setItem(key, token); 8 | } 9 | 10 | public removeToken(key: string) { 11 | localStorage.removeItem(key); 12 | } 13 | } 14 | 15 | export default new Token(); 16 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Router from './Router'; 3 | import UserContextProvider from '@/contexts/UserContextProvider'; 4 | 5 | function App() { 6 | return ( 7 |
8 | 9 | 10 | 11 |
12 | ); 13 | } 14 | 15 | export default App; 16 | -------------------------------------------------------------------------------- /src/components/common/Layout.tsx: -------------------------------------------------------------------------------- 1 | import { Outlet } from 'react-router-dom'; 2 | import Header from '@/components/header/Header'; 3 | import Footer from '@/components/common/Footer'; 4 | 5 | const Layout = () => { 6 | return ( 7 | <> 8 |
9 | 10 |