Skip to content

Commit

Permalink
Merge pull request #17 from woowacourse/feat/15-keyword
Browse files Browse the repository at this point in the history
feat: 로드맵 키워드 어드민 기능 구현
  • Loading branch information
euijinkk authored Dec 1, 2022
2 parents 30c3b21 + c9d3713 commit 9675e94
Show file tree
Hide file tree
Showing 33 changed files with 3,707 additions and 2,208 deletions.
35 changes: 35 additions & 0 deletions .github/workflows/admin-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: deploy for prod

on:
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-18.04

steps:
- name: Checkout Source Code
uses: actions/checkout@v2

- name: Cache node_modules
uses: actions/cache@v2
with:
path: '**/node_modules'
key: ${{ runner.os }}-node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-node-modules-
- name: Install Dependencies
run: |
yarn install
- name: Build
run: |
yarn build
env:
CI: false

- name: Deploy to S3
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: |
aws s3 cp --recursive --region ap-northeast-2 build s3://prolog-admin
38 changes: 38 additions & 0 deletions .github/workflows/admin-dev-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: deploy for dev

on:
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-18.04

steps:
- name: Checkout Source Code
uses: actions/checkout@v2

- name: Cache node_modules
uses: actions/cache@v2
with:
path: '**/node_modules'
key: ${{ runner.os }}-node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-node-modules-
- name: Install Dependencies
run: |
yarn install
- name: Build
run: |
yarn build
env:
CI: false

- name: Deploy to S3
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: |
aws s3 cp --recursive --region ap-northeast-2 build s3://prolog-dev-admin
- name: Invalidate CloudFront Cache
run: aws cloudfront create-invalidation --region ap-northeast-2 --distribution-id ${{secrets.AWS_CLOUDFRONT_DISTRIBUTION}} --paths "/*"
7 changes: 3 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

.env
/env

npm-debug.log*
yarn-debug.log*
Expand Down
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5",
"@tanstack/react-query": "^4.14.6",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^13.0.0",
Expand All @@ -16,12 +18,14 @@
"react": "^18.2.0",
"react-admin": "^4.2.6",
"react-dom": "^18.2.0",
"react-router-dom": "^6.4.3",
"react-scripts": "5.0.1",
"typescript": "^4.4.2",
"web-vitals": "^2.1.0"
},
"scripts": {
"start": "react-scripts start",
"start:dev": "cp ./env/.env.development ./.env && cross-env NODE_ENV=development react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
Expand All @@ -47,7 +51,9 @@
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.33.0",
"@typescript-eslint/parser": "^5.33.0",
"cross-env": "^7.0.3",
"eslint": "^8.21.0",
"eslint-plugin-react": "^7.30.1"
"eslint-plugin-react": "^7.30.1",
"prettier": "^2.7.1"
}
}
29 changes: 23 additions & 6 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { Admin, Resource, CustomRoutes } from 'react-admin';
import jsonServerProvider from 'ra-data-json-server';
import MissionCreate from './components/MissionCreate';
import Missions from './components/Missions';
import Sessions from './components/Sessions';
import SessionCreate from './components/SessionCreate';
import PopularStudylogsUpdate from './components/PopularStudylogsUpdate';
import MissionCreate from './reactAdminPages/MissionCreate';
import SessionCreate from './reactAdminPages/SessionCreate';
import { Route } from 'react-router-dom';
import MyLayout from './components/Layout';
import MyLayout from './Layout';
import { BASE_URL } from './client';
import Missions from './reactAdminPages/Missions';
import Sessions from './reactAdminPages/Sessions';
import PopularStudylogsUpdate from './customPages/PopularStudylogsUpdatePage';
import RoadmapSelectSessionPage from './customPages/RoadmapSelectSessionPage';
import RoadMapSelectTopKeywordPage from './customPages/RoadmapSelectTopKeywordPage';
import RoadmapTopKeywordsPage from './customPages/RoadmapTopKeywordsPage';
import RoadmapEditKeywordPage from './customPages/RoadmapEditKeywordPage';

const dataProvider = jsonServerProvider(BASE_URL);

Expand All @@ -18,6 +22,19 @@ function App() {
<Resource name="sessions" list={Sessions} create={SessionCreate} />
<CustomRoutes>
<Route path="/studylogs" element={<PopularStudylogsUpdate />} />
<Route path="/roadmap" element={<RoadmapSelectSessionPage />} />
<Route
path="/roadmap/:sessionId"
element={<RoadMapSelectTopKeywordPage />}
/>
<Route
path="/roadmap/:sessionId/:keywordId"
element={<RoadmapTopKeywordsPage />}
/>
<Route
path="/roadmap/:sessionId/editSubKeywords"
element={<RoadmapEditKeywordPage />}
/>
</CustomRoutes>
</Admin>
);
Expand Down
File renamed without changes.
6 changes: 6 additions & 0 deletions src/components/MyMenu.tsx → src/MyMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Menu } from 'react-admin';
import LabelIcon from '@mui/icons-material/Label';
import LibraryBooksIcon from '@mui/icons-material/LibraryBooks';
import WysiwygIcon from '@mui/icons-material/Wysiwyg';
import EditRoadIcon from '@mui/icons-material/EditRoad';

const MyMenu = (props: any) => (
<Menu {...props}>
Expand All @@ -16,6 +17,11 @@ const MyMenu = (props: any) => (
primaryText="인기있는 학습로그"
leftIcon={<LabelIcon />}
/>
<Menu.Item
to="/roadmap"
primaryText="로드맵"
leftIcon={<EditRoadIcon />}
/>
</Menu>
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Button from '@mui/material/Button';
import { useGetPopularStudylogs } from '../hooks/studylog';
import { useGetPopularStudylogs } from '../../hooks/studylog';

const PopularStudylogsUpdate = () => {
const { refetch } = useGetPopularStudylogs();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { Modal, Box, TextField } from '@mui/material';
import { useAddKeyword } from '../../../../hooks/roadmap';
import useInput from '../../../../hooks/useInput';
import {
validateDescription,
validateName,
validateImportance,
validateOrder,
} from '../../../../utils/validator';
import { AddKeywordModalProps } from './type';

export const AddKeywordModal = ({
open,
onClose,
sessionId,
parentKeywordId,
}: AddKeywordModalProps) => {
const name = useInput('', validateName);
const importance = useInput('', validateImportance);
const description = useInput('', validateDescription);
const order = useInput('', validateOrder);

const isAllValidated =
name.isValidated && description.isValidated && importance.isValidated;

const { mutate: addKeyword } = useAddKeyword({ successCallback: onClose });

return (
<Modal
open={open}
onClose={onClose}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box sx={style}>
<form
onSubmit={(event) => {
event.preventDefault();

if (name.value && importance.value && description.value) {
addKeyword({
sessionId,
name: name.value,
importance: Number(importance.value),
description: description.value,
order: Number(order.value),
parentKeywordId,
});
}
}}
>
<div>
<TextField
required
label="이름"
fullWidth
onChange={name.onChange}
value={name.value}
error={!name.isValidated}
helperText={name.message}
/>
</div>
<div>
<TextField
required
label="설명"
fullWidth
multiline
maxRows={4}
onChange={description.onChange}
value={description.value}
error={!description.isValidated}
helperText={description.message}
/>
</div>
<div>
<TextField
required
label="중요도"
fullWidth
onChange={importance.onChange}
value={importance.value}
error={!importance.isValidated}
helperText={importance.message}
/>
</div>
<div>
<TextField
required
label="순서"
fullWidth
onChange={order.onChange}
value={order.value}
error={!order.isValidated}
helperText={order.message}
/>
</div>
<div>
<TextField
required
disabled
label="상위 키워드 Id"
fullWidth
value={parentKeywordId}
/>
</div>
<button disabled={!isAllValidated}>키워드 추가</button>
</form>
</Box>
</Modal>
);
};

export const style = {
position: 'absolute' as const,
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 400,
bgcolor: 'background.paper',
border: '2px solid #646464',
boxShadow: 24,
p: 4,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export type AddKeywordModalProps = {
open: boolean;
onClose: () => void;
sessionId: number;
parentKeywordId: number | null;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { TableCell, Button } from '@mui/material';
import { useNavigate } from 'react-router-dom';
import { ChildrenKeyword } from '../../../../types';

export const CustomTableCell = ({
item,
sessionId,
}: {
item: ChildrenKeyword;
sessionId: number;
}) => {
const navigate = useNavigate();
return (
<>
{Object.values(item).map((itemValue, index) => {
if (Array.isArray(itemValue)) {
return (
<TableCell key={index} component="th" scope="row">
<Button
key={itemValue}
variant="contained"
onClick={() =>
navigate(`/roadmap/${sessionId}/editSubKeywords`, {
state: {
childrenKeywordList: itemValue,
sessionId,
name: item.name,
parentKeywordId: item.keywordId,
},
})
}
>
하위 키워드({itemValue.length}개) 목록 보기
</Button>
</TableCell>
);
}

return (
<TableCell key={index} component="th" scope="row">
{itemValue}
</TableCell>
);
})}
</>
);
};
Loading

0 comments on commit 9675e94

Please sign in to comment.