diff --git a/package.json b/package.json index 8db0452..bc2b221 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "@types/react-dom": "^16.9.8", "@types/react-intl": "^3.0.0", "@types/react-router-dom": "^5.1.5", + "@types/react-virtualized": "^9.21.10", "@types/recoil": "0.0.1", "@types/styled-components": "^5.1.1", "antd": "^4.4.2", @@ -24,8 +25,11 @@ "react": "^16.13.1", "react-dom": "^16.13.1", "react-intl": "^5.0.2", + "react-morefinity": "^1.0.4", "react-router-dom": "^5.2.0", "react-scripts": "3.4.1", + "react-virtualized": "^9.21.2", + "react-waypoint": "^9.0.3", "recoil": "0.0.10", "styled-components": "^5.1.1", "typescript": "~3.7.2" diff --git a/src/components/DefaultLayout/DefaultLayout.tsx b/src/components/DefaultLayout/DefaultLayout.tsx index c00e0d5..1109b14 100644 --- a/src/components/DefaultLayout/DefaultLayout.tsx +++ b/src/components/DefaultLayout/DefaultLayout.tsx @@ -193,6 +193,8 @@ const DefaultLayout: FunctionComponent = (props) => { padding: 24, margin: 0, minHeight: 280, + overflow: 'auto', + display: 'flex' }} > {children} diff --git a/src/components/DefaultLayout/DefaultLayoutLast.tsx b/src/components/DefaultLayout/DefaultLayoutLast.tsx new file mode 100644 index 0000000..4c7658c --- /dev/null +++ b/src/components/DefaultLayout/DefaultLayoutLast.tsx @@ -0,0 +1,200 @@ +import React, { FunctionComponent, useEffect, useMemo, ChangeEvent, useCallback } from "react"; +import { Layout, Menu, Breadcrumb, Input, Button } from "antd"; +import { useIntl } from "react-intl"; +import { routerMeta } from 'meta'; + +import { + UserOutlined, + LaptopOutlined, + NotificationOutlined, + SearchOutlined, + RadarChartOutlined +} from "@ant-design/icons"; +import { useLocation, useHistory } from "react-router-dom"; +import LanguageSelector from "components/LanguageSelector"; +import { assignRouteProps, propsToStyle, range } from "utils"; + +import LibiLogo from 'images/libi-logo.png'; +import ImageLogo from "components/ImageLogo"; +import styled, { CSSProperties } from "styled-components"; +import FlexCenter from "components/FlexCenter"; +import LoginModalButton from "components/LoginModalButton"; + +const { SubMenu } = Menu; +const { Header, Content, Sider } = Layout; + +interface IDefaultLayoutProps {} + +const defaultStyle = { + height: "100%", + backgroundColor: 'white' +}; + +const menuStyle = { + display: 'flex', + background: 'none', + border: 'none', + marginLeft: 'auto' +} + +const defaultMenus = Object.keys(routerMeta).reduce((prev: any[], componentKey: string) => { + const { path } = assignRouteProps(routerMeta[componentKey]) + console.log('path', path) + const slashLength: number = (path.match(/\//gi) || []).length + if (slashLength === 1 && path !== '/') { + return [ ...prev, { componentKey, path } ] + } else { + return prev + } +}, []) + +interface HeaderWrapperProps { + style?: CSSProperties +} + +const HeaderWrapper: any = styled.div` + display: -webkit-flex; + display: flex; + height: 64px; + width: 100%; + ${(props: HeaderWrapperProps) => propsToStyle(props.style || {})} +` + +const MockButtonsWrapper: any = styled.div` + display: -webkit-flex; + display: flex; + padding-right: 4px; + padding-left: 4px; + + & svg { + width: 60px; + height: 50px; + } + ${(props: HeaderWrapperProps) => propsToStyle(props.style || {})} +` + +const { Search } = Input; + +const MockButtons: any = ({ index }: any) => + +const DefaultLayout: FunctionComponent = (props) => { + const { children } = props; + const { formatMessage: fm } = useIntl(); + const { pathname } = useLocation(); + const history = useHistory(); + + const pathDom = useMemo(() => { + const pathArray = pathname.split('/') + const emptyToSpace = (text: string) => text === '' ? ' ' : text + return pathArray.map(path => {emptyToSpace(path)}) + }, [pathname]) + + const handleRouteClick = useCallback(({key}: any) => { + history.push(key) + }, [history]); + + return ( + +
+ + handleRouteClick({ key: '/' })} + className="logo" + image={LibiLogo} + style={{ width: 78, margin: "8px 8px" }} + /> + + {defaultMenus.map(({ componentKey, path }) => ( + {componentKey} + ))} + + + + + + + + + + + +
+ 당신의 가게에는 +
어떤 물건이 필요한가요? +
+ } + size="large" + onSearch={(value: string) => console.log(value)} + /> + {/*
*/} + + {/* + + {range(0, 10).map(v => { + return + })} + + */} +
+ + {/* */} + {pathDom} + + {children} + + {/* */} + +
+ ); +}; + +export default DefaultLayout; diff --git a/src/components/DefaultLayout/index.ts b/src/components/DefaultLayout/index.ts index 71c4033..ca0eca6 100644 --- a/src/components/DefaultLayout/index.ts +++ b/src/components/DefaultLayout/index.ts @@ -1,2 +1,2 @@ -import DefaultLayout from './DefaultLayout' +import DefaultLayout from './DefaultLayoutLast' export default DefaultLayout \ No newline at end of file diff --git a/src/components/ItemCard/ItemCard.tsx b/src/components/ItemCard/ItemCard.tsx new file mode 100644 index 0000000..3047a0c --- /dev/null +++ b/src/components/ItemCard/ItemCard.tsx @@ -0,0 +1,27 @@ +import React, { FunctionComponent } from "react"; + +import { Card } from "antd"; + +const { Meta } = Card; + +interface IItemCardProps {} + +const ItemCard: FunctionComponent = (props) => { + return ( + + } + > + + + ); +}; + +export default ItemCard; diff --git a/src/components/ItemCard/index.ts b/src/components/ItemCard/index.ts new file mode 100644 index 0000000..cd28fcd --- /dev/null +++ b/src/components/ItemCard/index.ts @@ -0,0 +1,2 @@ +import ItemCard from './ItemCard' +export default ItemCard \ No newline at end of file diff --git a/src/components/LoginForm/LoginForm.tsx b/src/components/LoginForm/LoginForm.tsx index be5e6fc..2cb5fe9 100644 --- a/src/components/LoginForm/LoginForm.tsx +++ b/src/components/LoginForm/LoginForm.tsx @@ -1,6 +1,8 @@ import React, { FunctionComponent, useCallback } from "react"; import { Form, Input, Button, Checkbox } from "antd"; +import RegisterModalButton from "components/RegisterModalButton"; +import FlexCenter from "components/FlexCenter"; interface ILoginFormProps {} @@ -50,11 +52,15 @@ const LoginForm: FunctionComponent = (props) => { Remember me - - + + + 아직 회원이 아니세요? + ); }; diff --git a/src/components/LoginModalButton/LoginModalButton.tsx b/src/components/LoginModalButton/LoginModalButton.tsx new file mode 100644 index 0000000..b3d8b49 --- /dev/null +++ b/src/components/LoginModalButton/LoginModalButton.tsx @@ -0,0 +1,39 @@ +import React, { useState, FunctionComponent, useCallback } from 'react'; +import { Button, Modal } from 'antd'; +import LoginForm from 'components/LoginForm'; + +interface ILoginModalProps { +} + +const LoginModalButton: FunctionComponent = (props) => { + const [visible, setVisible] = useState(false) + + const showModal = useCallback(() => { + setVisible(true) + }, []) + + const hideModal = useCallback(() => { + setVisible(false) + }, [setVisible]) + + const handleOk = useCallback(() => { + setVisible(false) + }, []) + + return <> + + + + + ; +}; + +export default LoginModalButton; diff --git a/src/components/LoginModalButton/index.ts b/src/components/LoginModalButton/index.ts new file mode 100644 index 0000000..94eddc8 --- /dev/null +++ b/src/components/LoginModalButton/index.ts @@ -0,0 +1,2 @@ +import LoginModalButton from './LoginModalButton' +export default LoginModalButton \ No newline at end of file diff --git a/src/components/RegisterForm/RegisterForm.tsx b/src/components/RegisterForm/RegisterForm.tsx new file mode 100644 index 0000000..dbab407 --- /dev/null +++ b/src/components/RegisterForm/RegisterForm.tsx @@ -0,0 +1,283 @@ +import React, { useState, FunctionComponent } from "react"; +import { + Form, + Input, + Tooltip, + Cascader, + Select, + Row, + Col, + Checkbox, + Button, + AutoComplete, +} from "antd"; +import { QuestionCircleOutlined } from "@ant-design/icons"; + +const { Option } = Select; +// const AutoCompleteOption = AutoComplete.Option; + +const residences = [ + { + value: "zhejiang", + label: "Zhejiang", + children: [ + { + value: "hangzhou", + label: "Hangzhou", + children: [ + { + value: "xihu", + label: "West Lake", + }, + ], + }, + ], + }, + { + value: "jiangsu", + label: "Jiangsu", + children: [ + { + value: "nanjing", + label: "Nanjing", + children: [ + { + value: "zhonghuamen", + label: "Zhong Hua Men", + }, + ], + }, + ], + }, +]; + +const formItemLayout = { + labelCol: { + xs: { span: 24 }, + sm: { span: 8 }, + }, + wrapperCol: { + xs: { span: 24 }, + sm: { span: 16 }, + }, +}; +const tailFormItemLayout = { + wrapperCol: { + xs: { + span: 24, + offset: 0, + }, + sm: { + span: 16, + offset: 8, + }, + }, +}; + +const RegistrationForm: FunctionComponent = () => { + const [form] = Form.useForm(); + + const onFinish = (values: any) => { + console.log("Received values of form: ", values); + }; + + const prefixSelector = ( + + + + ); + + const [autoCompleteResult, setAutoCompleteResult] = useState([]); + + const onWebsiteChange = (value: any) => { + if (!value) { + setAutoCompleteResult([]); + } else { + setAutoCompleteResult( + [".com", ".org", ".net"].map((domain: any) => `${value}${domain}`) + ); + } + }; + + const websiteOptions = autoCompleteResult.map((website) => ({ + label: website, + value: website, + })); + + return ( +
+ + + + + + + ({ + validator(rule, value) { + if (!value || getFieldValue("password") === value) { + return Promise.resolve(); + } + return Promise.reject( + "The two passwords that you entered do not match!" + ); + }, + }), + ]} + > + + + + Nickname  + + + + + } + rules={[ + { + required: true, + message: "Please input your nickname!", + whitespace: true, + }, + ]} + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + value + ? Promise.resolve() + : Promise.reject("Should accept agreement"), + }, + ]} + {...tailFormItemLayout} + > + + I have read the agreement + + + + + +
+ ); +}; + +export default RegistrationForm; diff --git a/src/components/RegisterForm/index.ts b/src/components/RegisterForm/index.ts new file mode 100644 index 0000000..da7bda8 --- /dev/null +++ b/src/components/RegisterForm/index.ts @@ -0,0 +1,2 @@ +import RegisterForm from './RegisterForm' +export default RegisterForm \ No newline at end of file diff --git a/src/components/RegisterModalButton/RegisterModalButton.tsx b/src/components/RegisterModalButton/RegisterModalButton.tsx new file mode 100644 index 0000000..0ee5c3b --- /dev/null +++ b/src/components/RegisterModalButton/RegisterModalButton.tsx @@ -0,0 +1,39 @@ +import React, { useState, FunctionComponent, useCallback } from 'react'; +import { Button, Modal } from 'antd'; +import RegisterForm from 'components/RegisterForm'; + +interface ILoginModalProps { +} + +const RegisterModalButton: FunctionComponent = (props) => { + const [visible, setVisible] = useState(false) + + const showModal = useCallback(() => { + setVisible(true) + }, []) + + const hideModal = useCallback(() => { + setVisible(false) + }, [setVisible]) + + const handleOk = useCallback(() => { + setVisible(false) + }, []) + + return <> + + + + + ; +}; + +export default RegisterModalButton; diff --git a/src/components/RegisterModalButton/index.ts b/src/components/RegisterModalButton/index.ts new file mode 100644 index 0000000..f2e6ecc --- /dev/null +++ b/src/components/RegisterModalButton/index.ts @@ -0,0 +1,2 @@ +import RegisterModalButton from './RegisterModalButton' +export default RegisterModalButton \ No newline at end of file diff --git a/src/components/WaypointListContainer/WaypointListContainer.tsx b/src/components/WaypointListContainer/WaypointListContainer.tsx new file mode 100644 index 0000000..93c6ac0 --- /dev/null +++ b/src/components/WaypointListContainer/WaypointListContainer.tsx @@ -0,0 +1,37 @@ +import React, { ReactNode } from "react"; +import { Waypoint } from "react-waypoint"; + +export interface IWaypointListContainerProps { + children: ReactNode; + onLoad: (args: any) => void; + isLastPage: boolean; + isLoading: boolean; + loadingComponent: ReactNode; + isActive: boolean; +} + +const WaypointListContainer = ({ + children, + onLoad, + isLastPage, + isLoading, + loadingComponent, + isActive, +}: IWaypointListContainerProps) => { + console.log('isActive', isActive) + console.log('onEnter', isActive ? onLoad : () => {}) + + return ( +
+ {children} + {isLoading && loadingComponent} + {!isLastPage && !isLoading && ( +
+ {}} /> +
+ )} +
+ ); +}; + +export default WaypointListContainer; diff --git a/src/components/WaypointListContainer/index.ts b/src/components/WaypointListContainer/index.ts new file mode 100644 index 0000000..cc6baef --- /dev/null +++ b/src/components/WaypointListContainer/index.ts @@ -0,0 +1,3 @@ +import WaypointListContainer from "./WaypointListContainer"; + +export default WaypointListContainer; diff --git a/src/containers/CardView/CardView.tsx b/src/containers/CardView/CardView.tsx new file mode 100644 index 0000000..c963a57 --- /dev/null +++ b/src/containers/CardView/CardView.tsx @@ -0,0 +1,221 @@ +import React, { FunctionComponent, useMemo, useEffect, useState, useCallback } from "react"; +import { Layout, Row, Col, Grid, Spin } from "antd"; +import ItemCard from "components/ItemCard"; +import WaypointListContainer from "components/WaypointListContainer"; + +interface ICardViewProps {} + +const breakPoint = { + xs: 24, + sm: 12, + md: 8, + lg: 6, + xl: 4, +}; + +const CardView: FunctionComponent = (props) => { + const [items, setItems] = useState([]); + const [loading, setLoading] = useState(false); + + useEffect(() => { + onLoad(); + }, []); + + const onLoad = useCallback(() => { + if (!loading) { + console.log('on load') + setLoading(true); + const actuallyLoadMore = (resolve: Function) => { + // fake new data + let newItems = []; + let s = items.length + 1; + for (let i = 0, l = 12; i < l; i++) { + newItems.push(Math.random() * 100); + } + setItems(items.concat(newItems)); + resolve(); + }; + new Promise((resolve, reject) => { + setTimeout(() => { + actuallyLoadMore(resolve); + setLoading(false); + }, 1000); + }); + } + }, [items, setItems, loading, setLoading]); + + console.log('loading', loading) + console.log('items.length', items.length) + + return ( +
+ {/* {screenKeys.reduce((prev: any, next: string, index: number) => { + screenKeys.length + return prev + }, {})} */} + } + isActive={true} + > + + {items.map((v: any, i: number) => ( + + + + ))} + + + {/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + */} +
+ ); +}; + +export default CardView; diff --git a/src/containers/CardView/index.ts b/src/containers/CardView/index.ts new file mode 100644 index 0000000..211af7f --- /dev/null +++ b/src/containers/CardView/index.ts @@ -0,0 +1,2 @@ +import CardView from './CardView' +export default CardView \ No newline at end of file diff --git a/src/containers/Register/Register.tsx b/src/containers/Register/Register.tsx new file mode 100644 index 0000000..8101cd9 --- /dev/null +++ b/src/containers/Register/Register.tsx @@ -0,0 +1,11 @@ +import React, { FunctionComponent } from 'react'; +import RegisterForm from 'components/RegisterForm'; + +interface ILoginProps { +} + +const Register: FunctionComponent = (props) => { + return ; +}; + +export default Register; diff --git a/src/containers/Register/index.ts b/src/containers/Register/index.ts new file mode 100644 index 0000000..3eb0b27 --- /dev/null +++ b/src/containers/Register/index.ts @@ -0,0 +1,2 @@ +import Register from './Register' +export default Register \ No newline at end of file diff --git a/src/meta/routerMeta.ts b/src/meta/routerMeta.ts index 33d1119..cc3e5ab 100644 --- a/src/meta/routerMeta.ts +++ b/src/meta/routerMeta.ts @@ -5,7 +5,9 @@ export type RouterMetaType = { [key: string] : (string | Omit