diff --git a/package-lock.json b/package-lock.json index 5769923..c4c9062 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "prop-types": "^15.8.1", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "^6.22.3", + "react-router-dom": "^6.23.0", "react-scripts": "5.0.1", "styled-components": "^6.1.8", "web-vitals": "^2.1.4", @@ -3603,9 +3603,9 @@ } }, "node_modules/@remix-run/router": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.3.tgz", - "integrity": "sha512-Oy8rmScVrVxWZVOpEF57ovlnhpZ8CCPlnIIumVcV9nFdiSIrus99+Lw78ekXyGvVDlIsFJbSfmSovJUhCWYV3w==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.16.0.tgz", + "integrity": "sha512-Quz1KOffeEf/zwkCBM3kBtH4ZoZ+pT3xIXBG4PPW/XFtDP7EGhtTiC2+gpL9GnR7+Qdet5Oa6cYSvwKYg6kN9Q==", "engines": { "node": ">=14.0.0" } @@ -16109,11 +16109,11 @@ } }, "node_modules/react-router": { - "version": "6.22.3", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.3.tgz", - "integrity": "sha512-dr2eb3Mj5zK2YISHK++foM9w4eBnO23eKnZEDs7c880P6oKbrjz/Svg9+nxqtHQK+oMW4OtjZca0RqPglXxguQ==", + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.23.0.tgz", + "integrity": "sha512-wPMZ8S2TuPadH0sF5irFGjkNLIcRvOSaEe7v+JER8508dyJumm6XZB1u5kztlX0RVq6AzRVndzqcUh6sFIauzA==", "dependencies": { - "@remix-run/router": "1.15.3" + "@remix-run/router": "1.16.0" }, "engines": { "node": ">=14.0.0" @@ -16123,12 +16123,12 @@ } }, "node_modules/react-router-dom": { - "version": "6.22.3", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.3.tgz", - "integrity": "sha512-7ZILI7HjcE+p31oQvwbokjk6OA/bnFxrhJ19n82Ex9Ph8fNAq+Hm/7KchpMGlTgWhUxRHMMCut+vEtNpWpowKw==", + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.23.0.tgz", + "integrity": "sha512-Q9YaSYvubwgbal2c9DJKfx6hTNoBp3iJDsl+Duva/DwxoJH+OTXkxGpql4iUK2sla/8z4RpjAm6EWx1qUDuopQ==", "dependencies": { - "@remix-run/router": "1.15.3", - "react-router": "6.22.3" + "@remix-run/router": "1.16.0", + "react-router": "6.23.0" }, "engines": { "node": ">=14.0.0" diff --git a/package.json b/package.json index 278309e..69adc1b 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "prop-types": "^15.8.1", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "^6.22.3", + "react-router-dom": "^6.23.0", "react-scripts": "5.0.1", "styled-components": "^6.1.8", "web-vitals": "^2.1.4", diff --git a/public/img/main.jpg b/public/img/main.jpg new file mode 100644 index 0000000..e13d6ba Binary files /dev/null and b/public/img/main.jpg differ diff --git a/src/App.js b/src/App.js index f969340..969b68a 100644 --- a/src/App.js +++ b/src/App.js @@ -21,28 +21,45 @@ const StyledLayout = styled.div` ` function App() { - const group_id = '662a83742c217fe65efaeab6' return (
- - - - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - + + } /> + } /> + } /> +
) } +function GroupRoutes() { + return ( + + + } /> + } /> + + + ) +} + +function GroupRoutesWithSidebar() { + return ( + + + + } /> + } /> + } /> + } /> + } /> + + + ) +} + export default App diff --git a/src/Components/Buttons/AddMemberButton.js b/src/Components/Buttons/AddMemberButton.js index a7d8180..d0f3435 100644 --- a/src/Components/Buttons/AddMemberButton.js +++ b/src/Components/Buttons/AddMemberButton.js @@ -15,17 +15,17 @@ const AddMember = ({ groupId }) => { const [email, setEmail] = useState('') const [phoneNumber, setPhoneNumber] = useState('') const [loading, setLoading] = useState(false) - const memberInfo = { - studentId, - email, - phoneNumber, + + const isAnyFieldEmpty = () => { + return !name || !studentId || !email || !phoneNumber } const handleAddMember = async () => { setLoading(true) - await addMember(groupId, name, memberInfo) + await addMember(groupId, name, { studentId, email, phoneNumber }) setLoading(false) setIsModalOpen(false) + alert('회원 추가가 완료되었습니다.') window.location.reload() } @@ -40,6 +40,7 @@ const AddMember = ({ groupId }) => { onOk={handleAddMember} onCancel={() => setIsModalOpen(false)} confirmLoading={loading} + okButtonProps={{ disabled: isAnyFieldEmpty() }} > setName(e.target.value)} /> setStudentId(e.target.value)} /> diff --git a/src/Components/Card/EventCard.js b/src/Components/Card/EventCard.js index eb00987..4eafabe 100644 --- a/src/Components/Card/EventCard.js +++ b/src/Components/Card/EventCard.js @@ -3,8 +3,6 @@ import { Collapse } from 'antd' import { getEvent } from '../../apis/event' import styled from 'styled-components' -const { Panel } = Collapse - const EventCard = ({ groupId }) => { const [events, setEvents] = useState([]) useEffect(() => { @@ -13,27 +11,44 @@ const EventCard = ({ groupId }) => { }) }, [groupId]) - return ( - - {events.map((event) => ( - -

- 설명: {event.description} -

-

- 회비: {event.fee} -

-
- ))} -
- ) + const formatDate = (date) => { + return new Date(date).toLocaleDateString() + } + + const items = events.map((event, i) => ({ + key: i, + label: events[i].name, + children: ( +
+

+ 설명: {events[i].description} +

+

+ 요금:{' '} + {typeof events[i].fee === 'number' ? events[i].fee.toLocaleString() + '원' : events[i].fee} +

+ +

+ 이벤트 기한: {formatDate(events[i].endDate)} +

+

+ 결제 기한: {formatDate(events[i].transactionEndDate)} +

+
+ ), + })) + + return } const StyledCollapse = styled(Collapse)` width: 60%; - margin-top: 100px; + margin-left: 100px; + margin-top: 50px; padding: 10px; background-color: rgba(0, 62.67, 151.94, 0.08); + overflow: auto; + max-height: 450px; ` export default EventCard diff --git a/src/Components/Card/GroupCard.js b/src/Components/Card/GroupCard.js index 382e928..d5fdfb4 100644 --- a/src/Components/Card/GroupCard.js +++ b/src/Components/Card/GroupCard.js @@ -1,38 +1,9 @@ -// GroupCard.js - import React, { useEffect, useState } from 'react' import { Card, Col, Row } from 'antd' import { Link } from 'react-router-dom' import { getGroups } from '../../apis/groups' import styled from 'styled-components' -import SideBar from '../SideBar/SideBar' -const StyledBox = styled.div` - display: flex; - width: 100%; -` -const StyledRow = styled(Row)` - width: 100%; - margin: 0 10px 10px 10px; - padding: 10px; -` - -const StyledCol = styled(Col)` - width: 100%; - margin: 0 10px 10px 10px; - padding: 10px; -` - -const StyledCard = styled(Card)` - width: 100%; - background-color: #f9fbff; - margin: 0 20px 20px 20px; - transition-duration: 0.3s, 0.3s; - border: 2px solid #f0f0f0; - &:hover { - background-color: #ecf4ff; - } -` const GroupCard = () => { const [groups, setGroups] = useState([]) @@ -41,22 +12,43 @@ const GroupCard = () => { setGroups(data) }) }, []) + + const renderGroupCards = () => { + return groups.map((group) => ( + + + + {group.description} + + + + )) + } + return ( - - - {groups.map((group) => ( - - - - {group.description} - - - ))} - - + {renderGroupCards()} ) } export default GroupCard + +const StyledBox = styled.div` + display: flex; + width: 100%; +` + +const StyledRow = styled(Row)` + width: 90%; +` + +const StyledCard = styled(Card)` + background-color: #f9fbff; + margin-left: 100px; + transition-duration: 0.3s, 0.3s; + border: 2px solid #f0f0f0; + &:hover { + background-color: #ecf4ff; + } +` diff --git a/src/Components/Forms/CreateEvent.js b/src/Components/Forms/CreateEvent.js index df7cae4..cbf47f1 100644 --- a/src/Components/Forms/CreateEvent.js +++ b/src/Components/Forms/CreateEvent.js @@ -9,18 +9,27 @@ const CreateEvent = ({ groupId }) => { const [description, setDescription] = useState('') const [startDate, setStartDate] = useState('') const [endDate, setEndDate] = useState('') - const [fee, setFee] = useState('') + const [transactionStartDate, setTransactionStartDate] = useState('') + const [transactionEndDate, setTransactionEndDate] = useState('') + const [fee, setFee] = useState(0) const [value, setValue] = useState(1) const eventInfo = { name, description, startDate, endDate, + transactionStartDate, + transactionEndDate, fee, } + const isAnyFieldEmpty = () => { + return !name || !description || !startDate || !endDate || !transactionStartDate || !transactionEndDate || !fee + } + const handleCreateEvent = async () => { await postEvent(groupId, eventInfo) + alert('이벤트가 생성되었습니다.') window.location.reload() } @@ -32,7 +41,7 @@ const CreateEvent = ({ groupId }) => { { style={{ width: '100%' }} /> + + { + setTransactionStartDate(dateString[0]) + setTransactionEndDate(dateString[1]) + }} + style={{ width: '100%' }} + /> + { }, ]} > - setFee(e.target.value)} /> + setFee(e.target.value)} /> @@ -111,8 +138,13 @@ const CreateEvent = ({ groupId }) => { - - + + 완료 @@ -126,7 +158,7 @@ CreateEvent.propTypes = { export default CreateEvent const StyledForm = styled(Form)` - margin: 30px; + width: 100%; ` // 폼을 감싸는 스타일드 컴포넌트 const StyledFormWrapper = styled.div` @@ -139,7 +171,7 @@ const StyledFormWrapper = styled.div` // 타이틀을 감싸는 스타일드 컴포넌트 const Title = styled.h1` - margin: 10px 40px; + margin: 10px 10px 0 20px; text-align: left; font-size: 32px; font-family: 'KoPubWorld Dotum'; @@ -149,24 +181,28 @@ const Title = styled.h1` // 폼 아이템을 감싸는 스타일드 컴포넌트 const StyledFormItems = styled(Form.Item)` .ant-form-item-label { - text-align: left; - margin-left: 40px; font-size: 24px; font-family: 'KoPubWorld Dotum'; font-weight: 700; word-wrap: break-word; } - .ant-input { - text-align: left; + + .ant-input, + .ant-picker { + width: 100%; font-size: 14px; - margin-top: 6px; + margin-top: 5px; + margin-left: 10px; } + .ant-btn { height: 50px; width: 100px; font-size: 24px; + margin-top: 10px; } ` + const StyledButton = styled(Button)` font-family: 'KoPubWorld Dotum'; font-weight: 700; @@ -176,6 +212,8 @@ const StyledRadio = styled(Radio)` display: flex; justify-content: left; margin-right: 400px; + margin-left: 20px; + margin-top: 5px; font-size: 16px; font-weight: 600; font-family: 'KoPubWorld Dotum'; diff --git a/src/Components/Forms/CreateForm.js b/src/Components/Forms/CreateForm.js index f3bebae..7eb12d3 100644 --- a/src/Components/Forms/CreateForm.js +++ b/src/Components/Forms/CreateForm.js @@ -2,10 +2,9 @@ import React, { useState } from 'react' import { Form, Input, Button } from 'antd' import { createGroup } from '../../apis/groups' import styled from 'styled-components' - +import { useNavigate } from 'react-router-dom' // 파일 업로드 시 실행되는 함수 const normFile = (e) => { - console.log('Upload event:', e) if (Array.isArray(e)) { return e } @@ -16,17 +15,20 @@ const CreateForm = () => { const [name, setName] = useState('') const [description, setDescription] = useState('') const [file, setFile] = useState(null) + const navigate = useNavigate() + + const isAnyFieldEmpty = () => { + return !name || !description + } const handleCreateGroup = async () => { const formData = new FormData() formData.append('name', name) formData.append('description', description) formData.append('memberExcel', file) - await createGroup(formData).then((res) => { - console.log(res) - }) + await createGroup(formData) alert('모임이 생성되었습니다.') - window.location.reload() + navigate('/group') } const handleFileChange = (e) => { @@ -64,8 +66,13 @@ const CreateForm = () => { - - @@ -77,7 +84,6 @@ export default CreateForm // 전체 폼을 감싸는 스타일드 컴포넌트 const StyledForm = styled(Form)` - margin: 30px; width: 100%; ` // 폼을 감싸는 스타일드 컴포넌트 @@ -86,7 +92,7 @@ const StyledFormWrapper = styled.div` border-radius: 10px; background-color: rgba(0, 62.67, 151.94, 0.08); max-width: 800px; - margin: 10px auto; + margin: 40px auto; ` // 타이틀을 감싸는 스타일드 컴포넌트 @@ -117,6 +123,5 @@ const StyledFormItems = styled(Form.Item)` height: 50px; width: 100px; font-size: 24px; - margin: 5% 0 0 40%; } ` diff --git a/src/Components/NavBar/NavBar.js b/src/Components/NavBar/NavBar.js index 54fb233..5aec4f9 100644 --- a/src/Components/NavBar/NavBar.js +++ b/src/Components/NavBar/NavBar.js @@ -14,7 +14,7 @@ const items = [ }, { key: 'myGroups', - label: 나의 모임, + label: 나의 모임, }, { key: 'myProfile', diff --git a/src/Components/SideBar/SideBar.js b/src/Components/SideBar/SideBar.js index 3ff2087..1a848da 100644 --- a/src/Components/SideBar/SideBar.js +++ b/src/Components/SideBar/SideBar.js @@ -2,12 +2,10 @@ import { Link } from 'react-router-dom' // eslint-disable-line no-unused-vars import React, { useState } from 'react' // eslint-disable-line no-unused-vars import styled from 'styled-components' // eslint-disable-line no-unused-vars import { NavLink } from 'react-router-dom' -import { useEffect } from 'react' -import { getMember } from '../../apis/members' import propTypes from 'prop-types' const StyledSideBarBox = styled.div` - width: 30%; + width: 20%; height: 500px; // background-color: #b9b9b9; ` @@ -42,17 +40,17 @@ const StyledNavLink = styled(NavLink)` border-left: 4px solid rgb(0, 63, 150); } ` -const SideBar = ({ group_id }) => { +const SideBar = () => { const memberData = [ { index: 1, name: '회원명단업로드', - path: `group/${group_id}/uploadMember`, + path: `uploadMember`, }, { index: 2, name: '회원 목록', - path: `group/${group_id}/showGroupDetails`, + path: `showGroupDetails`, }, ] @@ -60,12 +58,12 @@ const SideBar = ({ group_id }) => { { index: 1, name: '이벤트 생성', - path: `/group/${group_id}/createEvent`, + path: `createEvent`, }, { index: 2, name: '이벤트 목록', - path: `/group/${group_id}/showEvent`, + path: `showEventList`, }, ] @@ -73,12 +71,12 @@ const SideBar = ({ group_id }) => { { index: 1, name: '모임 정보 변경', - path: `/group/${group_id}/editInfo`, + path: `editInfo`, }, { index: 2, name: '부매니저 설정', - path: `group/${group_id}/setSubMng`, + path: `setSubMng`, }, ] @@ -86,29 +84,20 @@ const SideBar = ({ group_id }) => { { index: 1, name: '거래내역 업로드', - path: `group/${group_id}/uploadResult`, + path: `uploadResult`, }, { index: 2, name: '이벤트별 조회', - path: `group/${group_id}/showResult`, + path: `showResult`, }, { index: 3, name: '거래내역분석', - path: `group/${group_id}/showResult`, + path: `showResult`, }, ] - const [members, setMembers] = useState([]) - const groupId = window.location.href.split('/')[4] - useEffect(() => { - getMember(groupId).then((data) => { - setMembers(data) - }) - }, [groupId]) - console.log(members) - if (window.location.pathname === '/group' || window.location.pathname === '/') return null return ( @@ -117,7 +106,7 @@ const SideBar = ({ group_id }) => { 회원 {memberData.map((data) => ( - +  {data.name} @@ -127,7 +116,7 @@ const SideBar = ({ group_id }) => { 이벤트 {eventData.map((data) => ( - +  {data.name} @@ -138,7 +127,7 @@ const SideBar = ({ group_id }) => { {settingData.map((data) => ( - +  {data.name} @@ -149,7 +138,7 @@ const SideBar = ({ group_id }) => { {transactionData.map((data) => ( - +  {data.name} diff --git a/src/Components/Tables/Tables.js b/src/Components/Tables/Tables.js index cec7832..124ff53 100644 --- a/src/Components/Tables/Tables.js +++ b/src/Components/Tables/Tables.js @@ -22,8 +22,6 @@ const Tables = ({ groupId }) => { setMemberKeys(keys) }, [members]) - console.log(memberKeys) - const columns = [ { title: '순', @@ -71,7 +69,7 @@ const Tables = ({ groupId }) => { } return ( - <> + @@ -84,15 +82,23 @@ const Tables = ({ groupId }) => { pagination={false} scroll={{ y: 450 }} /> - + ) } +const Wrapper = styled.div` + width: 100%; + border-radius: 20px; + background-color: rgba(0, 62.67, 151.94, 0.04); + max-width: 750px; + margin-left: 170px; + margin-top: 20px; +` const ButtonWrapper = styled.div` display: flex; justify-content: flex-end; - gap: 10px; - margin-bottom: 10px; + gap: 5px; + padding: 10px; ` const StyledTable = styled(Table)` diff --git a/src/Components/Upload/UploadMember.js b/src/Components/Upload/UploadMember.js index 8a67129..50b3ecf 100644 --- a/src/Components/Upload/UploadMember.js +++ b/src/Components/Upload/UploadMember.js @@ -3,12 +3,14 @@ import { uploadMember } from '../../apis/members' import { InboxOutlined } from '@ant-design/icons' import { Upload, Button } from 'antd' import styled from 'styled-components' +import { useNavigate } from 'react-router-dom' const { Dragger } = Upload const UploadMember = ({ groupId }) => { const [file, setFile] = useState(null) const [isFileUploaded, setIsFileUploaded] = useState(false) + const navigate = useNavigate() const props = { name: 'file', @@ -23,11 +25,9 @@ const UploadMember = ({ groupId }) => { } const handleUpload = async () => { - await uploadMember(groupId, file).then((res) => { - console.log(res) - }) + await uploadMember(groupId, file) alert('파일이 업로드되었습니다.') - window.location.reload() + navigate(`/group/${groupId}/showGroupDetails`) } return ( @@ -68,7 +68,6 @@ export const StyledButton = styled(Button)` font-size: 20px; font-weight: 500; - //글씨 수직 맞추기 display: flex; justify-content: center; align-items: center; @@ -85,8 +84,9 @@ export const StyledDragger = styled(Dragger)` export const Wrapper = styled.div` display: flex; flex-direction: column; - align-items: end; + align-items: flex-end; width: 50%; + margin-left: 12%; ` const FileIconWrapper = styled.div` width: 100%; diff --git a/src/Pages/GroupMainPage/index.js b/src/Pages/GroupMainPage/index.js index 2bfd710..f9046eb 100644 --- a/src/Pages/GroupMainPage/index.js +++ b/src/Pages/GroupMainPage/index.js @@ -1,8 +1,38 @@ -import React from 'react' +import React, { useEffect } from 'react' +import styled from 'styled-components' +import { getGroups } from '../../apis/groups' + // import styled from 'styled-components' const GroupMainPage = () => { - return
그룹 메인 페이지 (새로고침 한 번만 해주세요 ... )
+ const [groups, setGroups] = React.useState([]) + useEffect(() => { + getGroups().then((data) => { + setGroups(data) + }) + }, []) + + return ( +
+ +
+ {groups.map((group) => ( +
+

{group.name}

+

모임소개: {group.description}

+
+ ))} +
+
+ ) } +const StyledImg = styled.img` + width: 1000px; + height: 300px; + margin-top: 50px; + object-fit: cover; + float: left; +` + export default GroupMainPage diff --git a/src/Pages/MainPage/index.js b/src/Pages/MainPage/index.js index 6993cc9..6af1014 100644 --- a/src/Pages/MainPage/index.js +++ b/src/Pages/MainPage/index.js @@ -9,14 +9,12 @@ const MainPage = () => { navigate('/group') } - return (
환영합니다... 로그인하기...

-
) } diff --git a/src/Pages/ShowGroupDetails/index.js b/src/Pages/ShowGroupDetails/index.js index 05696d4..9448f54 100644 --- a/src/Pages/ShowGroupDetails/index.js +++ b/src/Pages/ShowGroupDetails/index.js @@ -1,23 +1,12 @@ import React from 'react' -import styled from 'styled-components' import Tables from '../../Components/Tables/Tables' -const Wrapper = styled.div` - padding: 10px; - border-radius: 20px; - background-color: rgba(0, 62.67, 151.94, 0.04); - max-width: 680px; - margin: 10px 60px; -` - const ShowGroupDetails = () => { const groupId = window.location.href.split('/')[4] return (
- - - +
) } diff --git a/src/Pages/ShowGroupList/index.js b/src/Pages/ShowGroupList/index.js index eb8e681..887b8a3 100644 --- a/src/Pages/ShowGroupList/index.js +++ b/src/Pages/ShowGroupList/index.js @@ -4,23 +4,6 @@ import styled from 'styled-components' import { useNavigate } from 'react-router-dom' import { Button } from 'antd' -const StyledGroupListLayout = styled.div` - display: flex; - flex-direction: column; - width: 100%; -` - -const StyledGroupPageLayout = styled.div` - display: flex; - flex-direction: column; - width: 100%; -` - -const StyledButtonSection = styled.div` - display: flex; - padding: 5px 80%; -` - const ShowGroupList = () => { const navigate = useNavigate() const onClickCreateGroup = () => { @@ -29,9 +12,9 @@ const ShowGroupList = () => { return ( - + @@ -42,3 +25,36 @@ const ShowGroupList = () => { } export default ShowGroupList + +const StyledGroupListLayout = styled.div` + display: flex; + flex-direction: column; + width: 100%; +` + +const StyledGroupPageLayout = styled.div` + display: flex; + flex-direction: column; + width: 100%; +` + +const StyledButtonSection = styled.div` + display: flex; + justify-content: flex-end; + margin-right: 155px; + padding: 5px; +` + +const StyledButton = styled(Button)` + margin-top: 20px; + margin-bottom: 10px; + width: 120px; + height: 40px; + font-size: 20px; + font-weight: 500; + + display: flex; + justify-content: center; + align-items: center; + background-color: #003e97; +` diff --git a/src/apis/groups.js b/src/apis/groups.js index f776bc0..80ca9ba 100644 --- a/src/apis/groups.js +++ b/src/apis/groups.js @@ -12,7 +12,6 @@ export const getGroupDetail = async (groupId) => { } export const createGroup = async (groupInfo) => { - console.log(groupInfo) const response = await formApi.post('/group', groupInfo) return response.data } diff --git a/src/apis/members.js b/src/apis/members.js index 591a79c..6226cb1 100644 --- a/src/apis/members.js +++ b/src/apis/members.js @@ -27,9 +27,6 @@ export const deleteMember = async (groupId, memberId) => { } export const uploadMember = async (groupId, file) => { - console.log(groupId) - console.log(file) - const formData = new FormData() formData.append('memberFile', file) const response = await formApi.post(`group/${groupId}/member/excel`, formData)