diff --git a/package.json b/package.json index 39b9ea8..bbd3a72 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "@babel/preset-react": "^7.0.0", "@babel/preset-typescript": "^7.8.3", "@babel/runtime": "^7.0.0", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", "@types/classnames": "^2.2.10", "@types/jest": "^24.9.0", "@types/lodash": "^4.14.149", @@ -47,7 +48,6 @@ "@types/react-router-dom": "^5.1.3", "@typescript-eslint/eslint-plugin": "^4.19.0", "@typescript-eslint/parser": "^4.19.0", - "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", "babel-jest": "28.1.1", "babel-loader": "^8.2.3", "babel-plugin-dynamic-import-node": "^2.2.0", @@ -55,20 +55,20 @@ "babel-plugin-react-require": "^3.0.0", "babel-plugin-react-transform": "^3.0.0", "cookie-parser": "^1.4.3", - "css-loader": "^5.2.6", "css-hot-loader": "^1.4.4", + "css-loader": "^5.2.6", "enzyme": "^3.9.0", "enzyme-adapter-react-16": "^1.9.1", "eslint": "^7.11.0", "eslint-import-resolver-webpack": "^0.13.0", - "eslint-webpack-plugin": "^3.1.1", "eslint-plugin-babel": "^5.3.1", "eslint-plugin-import": "^2.22.1", "eslint-plugin-react": "^7.7.0", "eslint-rich-reporter": "^0.0.10", + "eslint-webpack-plugin": "^3.1.1", "extract-text-webpack-plugin": "^4.0.0-beta.0", - "friendly-errors-webpack-plugin": "^1.7.0", "fork-ts-checker-webpack-plugin": "^6.5.0", + "friendly-errors-webpack-plugin": "^1.7.0", "html-webpack-plugin": "^5.5.0", "husky": "^1.3.1", "identity-obj-proxy": "^3.0.0", @@ -98,6 +98,7 @@ "axios": "^0.21.1", "classnames": "^2.2.5", "commander": "^5.1.0", + "immer": "^9.0.15", "lodash": "^4.17.19", "lodash-decorators": "^4.5.0", "moment": "^2.29.1", @@ -109,7 +110,8 @@ "recoil": "^0.7.4", "redux": "^4.0.5", "redux-thunk": "^2.3.0", - "typescript": "^4.4.2" + "typescript": "^4.4.2", + "use-immer": "^0.7.0" }, "husky": { "hooks": { diff --git a/src/components/App/index.js b/src/components/App/index.js index 4eeff5a..6103b40 100644 --- a/src/components/App/index.js +++ b/src/components/App/index.js @@ -2,6 +2,7 @@ import {BrowserRouter, Route, Switch, Redirect} from 'react-router-dom'; import {Provider} from 'react-redux'; import {RecoilRoot} from 'recoil'; import {store} from '@/store'; +import JiraGenerator from '@/components/Home/JiraGenerator'; import {Home} from '..'; import styles from './styles.less'; @@ -12,6 +13,7 @@ const App = () => (
+
diff --git a/src/components/Home/JiraGenerator.less b/src/components/Home/JiraGenerator.less new file mode 100644 index 0000000..581e0cd --- /dev/null +++ b/src/components/Home/JiraGenerator.less @@ -0,0 +1,10 @@ +.list { + display: flex; + width: 100%; + align-items: center; + justify-content: flex-start; + + & > * + * { + margin-left: 20px; + } +} diff --git a/src/components/Home/JiraGenerator.tsx b/src/components/Home/JiraGenerator.tsx new file mode 100644 index 0000000..e9e9d62 --- /dev/null +++ b/src/components/Home/JiraGenerator.tsx @@ -0,0 +1,121 @@ +import {Input, InputNumber, Button, List, Divider} from 'antd'; +import {useCallback, useState} from 'react'; +import {cloneDeep, partial} from 'lodash'; +// why unresolved +// eslint-disable-next-line import/no-unresolved +import {produce} from 'immer'; +import styles from './JiraGenerator.less'; + +// - [FE] / assignee:"wenwei.zhang@shopee.com" cfield:"Story Points:1" + +const templateRow = { + summary: '', + assignee: '', + storyPoint: 1, +}; + +type Row = typeof templateRow; + +const JiraGenerator = () => { + const [list, setList] = useState([cloneDeep(templateRow)]); + const [result, setResult] = useState([]); + + + const handleAdd = useCallback( + () => { + setList(prev => [...prev, cloneDeep(templateRow)]); + }, + [] + ); + + const handleRowChange = useCallback( + (index: number, key: string, value: string | number) => { + const result = produce(list, draft => { + const target = draft[index]; + target[key] = value; + }); + setList(result); + }, + [list] + ); + + const handleInputEvent = useCallback( + (index: number, key: string, e) => { + handleRowChange(index, key, e.target.value); + }, + [handleRowChange] + ); + + const handleGenerateClick = useCallback( + () => { + const str = list.map(item => ( + // eslint-disable-next-line max-len + `- [FE]${item.summary} / assignee:"${item.assignee}@shopee.com" cfield:"Story Points:${item.storyPoint}"` + )).join('\n'); + setResult(prev => [str, ...prev]); + }, + [list] + ); + + return ( +
+ Jira Generator + { + return ( + +
+ Summary: + +
+
+ Assignee: + + @shopee.com +
+
+ {'Story Points:'} + +
+
+ ); + }} + /> + + + +
+

Result:

+ ( + +
{item}
+
+ )} + /> +
+
+ ); +}; + +export default JiraGenerator; diff --git a/yarn.lock b/yarn.lock index c22c134..ab4bb23 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5712,6 +5712,11 @@ image-size@~0.5.0: resolved "https://registry.npm.taobao.org/image-size/download/image-size-0.5.5.tgz?cache=0&sync_timestamp=1569841504754&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fimage-size%2Fdownload%2Fimage-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w= +immer@^9.0.15: + version "9.0.15" + resolved "https://registry.npmmirror.com/immer/-/immer-9.0.15.tgz#0b9169e5b1d22137aba7d43f8a81a495dd1b62dc" + integrity sha512-2eB/sswms9AEUSkOm4SbV5Y7Vmt/bKRwByd52jfLkW4OLYeaTP3EEiJ9agqU0O/tq6Dk62Zfj+TJSqfm1rLVGQ== + import-fresh@^2.0.0: version "2.0.0" resolved "https://registry.npm.taobao.org/import-fresh/download/import-fresh-2.0.0.tgz?cache=0&sync_timestamp=1573665028675&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fimport-fresh%2Fdownload%2Fimport-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" @@ -10866,6 +10871,11 @@ url@^0.11.0: punycode "1.3.2" querystring "0.2.0" +use-immer@^0.7.0: + version "0.7.0" + resolved "https://registry.npmmirror.com/use-immer/-/use-immer-0.7.0.tgz#e3bfbb806b5e3ff6e37441be74c306d91c1e0962" + integrity sha512-Re4hjrP3a/2ABZjAc0b7AK9s626bnO+H33RO2VUhiDZ2StBz5B663K6WNNlr4QtHWaGUmvLpwt3whFvvWuolQw== + use@^3.1.0: version "3.1.1" resolved "https://registry.npm.taobao.org/use/download/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"