Skip to content

Commit

Permalink
feat: 회원추가, 회원삭제 기능 추가 (#13)
Browse files Browse the repository at this point in the history
Co-authored-by: 조준호 <[email protected]>
  • Loading branch information
dassasa and 조준호 authored Apr 21, 2024
1 parent 3518d2f commit 2510b22
Show file tree
Hide file tree
Showing 9 changed files with 289 additions and 71 deletions.
1 change: 1 addition & 0 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ function App() {
<div className="App">
<NavBar />
<Routes>
<Route path="/" element={<div>Home</div>} />
<Route path="/createGroup" element={<CreateGroup />} />
<Route path="/showGroupList" element={<ShowGroupList />} />
<Route path="/group/:id/showGroupDetails" element={<ShowGroupDetails />} />
Expand Down
54 changes: 54 additions & 0 deletions src/Components/Buttons/AddMemberButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React, { useState } from 'react'
import { addMember } from '../../apis/members'
import { Button, Modal, Input } from 'antd'
import styled from 'styled-components'
import PropTypes from 'prop-types'

const StyledInput = styled(Input)`
margin-bottom: 5px;
`

const AddMember = ({ groupId }) => {
const [isModalOpen, setIsModalOpen] = useState(false)
const [name, setName] = useState('')
const [studentId, setStudentId] = useState('')
const [phoneNumber, setPhoneNumber] = useState('')
const [loading, setLoading] = useState(false)

const handleAddMember = async () => {
setLoading(true)
await addMember(groupId, name, phoneNumber)
setLoading(false)
setIsModalOpen(false)
window.location.reload()
}

return (
<>
<Button type="primary" onClick={() => setIsModalOpen(true)}>
회원 추가
</Button>
<Modal
title="회원 추가"
open={isModalOpen}
onOk={handleAddMember}
onCancel={() => setIsModalOpen(false)}
confirmLoading={loading}
>
<StyledInput placeholder="이름" value={name} onChange={(e) => setName(e.target.value)} />
<StyledInput placeholder="학번" value={studentId} onChange={(e) => setStudentId(e.target.value)} />
<StyledInput
placeholder="전화번호"
value={phoneNumber}
onChange={(e) => setPhoneNumber(e.target.value)}
/>
</Modal>
</>
)
}

AddMember.propTypes = {
groupId: PropTypes.string.isRequired,
}

export default AddMember
36 changes: 36 additions & 0 deletions src/Components/Buttons/DeleteMemberButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react'
import { Button, Popconfirm, message } from 'antd'
import PropTypes from 'prop-types'
import { deleteMember } from '../../apis/members'

const DeleteMember = ({ groupId, memberIds }) => {
const handleDelete = async () => {
await deleteMember(groupId, memberIds)
window.location.reload()
}
const confirmDelete = () => {
if (memberIds.length === 0) {
message.error('선택한 회원이 없습니다.')
return
}
handleDelete()
}
return (
<Popconfirm
title="정말 삭제하시겠습니까?"
onConfirm={confirmDelete}
okText="삭제"
cancelText="아니요"
disabled={memberIds.length === 0}
>
<Button type="primary">회원 삭제</Button>
</Popconfirm>
)
}

DeleteMember.propTypes = {
groupId: PropTypes.string.isRequired,
memberIds: PropTypes.arrayOf(PropTypes.string).isRequired,
}

export default DeleteMember
33 changes: 33 additions & 0 deletions src/Components/GroupCard/GroupCard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// 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'

const GroupCard = () => {
const [groups, setGroups] = useState([])

useEffect(() => {
getGroups().then((data) => {
setGroups(data)
})
}, [])
return (
<div>
<Row gutter={16}>
<Col span={8}>
{groups.map((group) => (
<Link to={`/group/${group._id}/showGroupDetails`} key={group._id}>
<Card title={group.name} bordered={false}>
{group.description}
</Card>
</Link>
))}
</Col>
</Row>
</div>
)
}

export default GroupCard
8 changes: 4 additions & 4 deletions src/Components/NavBar/NavBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ const NavBar = () => {

const items = [
{
key: 'myGroups',
label: <Link to="/showGroupList">나의 그룹</Link>,
key: 'home',
label: <Link to="/">썸타임 로고 자리</Link>,
},
{
key: 'myEvents',
label: <Link to="/showEventList">나의 이벤트</Link>,
key: 'myGroups',
label: <Link to="/showGroupList">나의 모임</Link>,
},
{
key: 'myProfile',
Expand Down
119 changes: 119 additions & 0 deletions src/Components/Tables/Tables.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import React, { useEffect, useState } from 'react'
import { Table } from 'antd'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import AddMemberButton from '../Buttons/AddMemberButton'
import DeleteMemberButton from '../Buttons/DeleteMemberButton'

const Tables = ({ members, groupId }) => {
const columns = [
{
title: '순',
dataIndex: 'index',
},
{
title: '이름',
dataIndex: 'name',
},
{
title: '학번',
dataIndex: 'studentId',
},
{
title: '전화번호',
dataIndex: 'phoneNumber',
},
{
title: '비고',
dataIndex: 'remark',
},
]

const data = []
for (let i = 0; i < members.length; i++) {
data.push({
_id: members[i]._id,
key: i,
index: i + 1,
name: members[i].name,
/*
studentId: members[i].memberInfo.studentId,
phoneNumber: members[i].memberInfo.phone,
remark: members[i].memberInfo.remark,
*/
})
}

const [selectedRowKeys, setSelectedRowKeys] = useState([])
const [selectedRows, setSelectedRows] = useState([])
const [deleteMemberIds, setDeleteMemberIds] = useState([])

useEffect(() => {
const ids = selectedRows.map((row) => row._id)
setDeleteMemberIds(ids)
}, [selectedRows])

const onSelectChange = (selectedRowKeys, selectedRows) => {
setSelectedRowKeys(selectedRowKeys)
setSelectedRows(selectedRows)
}

const rowSelection = {
selectedRowKeys,
onChange: onSelectChange,
}

return (
<>
<AddMemberButton groupId={groupId} />
<DeleteMemberButton groupId={groupId} memberIds={deleteMemberIds} />

<StyledTable
rowSelection={rowSelection}
columns={columns}
dataSource={data}
pagination={false}
scroll={{ y: 450 }}
/>
</>
)
}

const StyledTable = styled(Table)`
.ant-table-row {
background-color: ${(props) =>
props.hoveredRow === props.rowKey ? 'rgba(0, 62.67, 151.94, 0.04)' : 'transparent'};
}
.ant-table-thead > tr > th {
border-bottom: 2px solid #d9d9d9;
font-size: 15px;
font-weight: 700;
text-align: center;
background-color: rgba(0, 62.67, 151.94, 0.04);
}
.ant-table-tbody > tr > td {
border-bottom: 1px solid #d9d9d9;
font-size: 15px;
text-align: center;
padding: 10px;
background-color: rgba(0, 62.67, 151.94, 0.04);
}
.ant-table-tbody > tr:last-child > td {
border-bottom: none;
}
`
Tables.propTypes = {
members: PropTypes.arrayOf(
PropTypes.shape({
_id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
memberInfo: PropTypes.shape({
studentId: PropTypes.string.isRequired,
phone: PropTypes.string.isRequired,
remark: PropTypes.string.isRequired,
}),
}),
).isRequired,
groupId: PropTypes.string.isRequired,
}
export default Tables
49 changes: 20 additions & 29 deletions src/Pages/ShowGroupDetails/index.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,30 @@
import React from 'react'
import React, { useEffect, useState } from 'react'
import styled from 'styled-components'
import { Tabs } from 'antd'
import dummy from '../../db/data.json'
import { getMember } from '../../apis/members'
import Tables from '../../Components/Tables/Tables'

const Wrapper = styled.div`
padding: 10px;
border-radius: 10px;
background-color: rgba(0, 62.67, 151.94, 0.08);
max-width: 400px;
border-radius: 20px;
background-color: rgba(0, 62.67, 151.94, 0.04);
max-width: 680px;
margin: 10px 60px;
`
const onChange = (key) => {
console.log(key)
}
/* Read 구현 필요 */
const items = [
{
key: '1',
label: '회원',
children: '그룹 정보',
},
{
key: '2',
label: '이벤트',
children: '그룹 멤버',
},
]
console.log(dummy)

const ShowGroupDetails = () => {
const [members, setMembers] = useState([])
const groupId = window.location.href.split('/')[4]
useEffect(() => {
getMember().then((data) => {
setMembers(data)
console.log(getMember)
})
}, [])

return (
<>
<h1>안녕</h1>
<Wrapper>
<Tabs defaultActiveKey="1" items={items} onChange={onChange}></Tabs>
</Wrapper>
</>
<Wrapper>
<Tables members={members} groupId={groupId} />
</Wrapper>
)
}

Expand Down
40 changes: 4 additions & 36 deletions src/Pages/ShowGroupList/index.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,12 @@
import React, { useEffect, useState } from 'react'
import PropTypes from 'prop-types'
import { Card, Col, Row } from 'antd'
import { Link } from 'react-router-dom'
import { getGroups } from '../../apis/groups'
const ShowGroupList = () => {
const [groups, setGroups] = useState([])

useEffect(() => {
getGroups().then((data) => {
setGroups(data)
})
}, [])
import React from 'react'
import GroupCard from '../../Components/GroupCard/GroupCard'

const ShowGroupList = () => {
return (
<div>
<Row gutter={16}>
<Col span={8}>
{groups.map((group) => (
<GroupCard key={group._id} group={group} />
))}
</Col>
</Row>
<GroupCard />
</div>
)
}

const GroupCard = ({ group }) => {
return (
<Link to={`/group/${group._id}/showGroupDetails`}>
<Card title={group.name} style={{ marginBottom: '16px' }}>
<p>{group.description}</p>
</Card>
</Link>
)
}
GroupCard.propTypes = {
group: PropTypes.shape({
_id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
description: PropTypes.string.isRequired,
}).isRequired,
}
export default ShowGroupList
Loading

0 comments on commit 2510b22

Please sign in to comment.