Skip to content

Commit

Permalink
RC Student Table (#66)
Browse files Browse the repository at this point in the history
  • Loading branch information
BlueHorn07 authored Feb 17, 2024
1 parent cd7d931 commit be65a95
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 50 deletions.
9 changes: 8 additions & 1 deletion components/common/csv-upload.form.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useState } from "react";
import { Button, Form } from "semantic-ui-react"
import { CsvUpload } from "@/utils/file-upload";
import { Axios } from "axios";
import { PoPoAxios } from "@/utils/axios.instance";

const CsvUploadForm = ({ label, uploadUri }) => {
Expand All @@ -15,11 +14,19 @@ const CsvUploadForm = ({ label, uploadUri }) => {
accept={'csv'}
onChange={async (evt) => {
const file = evt.target.files[0];
if (!file.name.includes('.csv')) {
alert('CSV 파일만 업로드 가능합니다.');
return;
}
setUploadedFile(file);
}}
/>

<Button onClick={async () => {
if (!uploadedFile.name.includes('.csv')) {
alert('CSV 파일만 업로드 가능합니다.');
return;
}
CsvUpload(uploadUri, uploadedFile)
.catch(err => {
const errMsg = err.response.data.message;
Expand Down
36 changes: 36 additions & 0 deletions components/user/rc-user.table.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Table } from 'semantic-ui-react'

const RcUserTable = ({ userStatusList }) => {
return (
<Table
celled selectable
textAlign={'center'}>
<Table.Header>
<Table.Row>
<Table.HeaderCell>idx.</Table.HeaderCell>
<Table.HeaderCell>이름</Table.HeaderCell>
<Table.HeaderCell>이메일</Table.HeaderCell>
<Table.HeaderCell>POPO 이름</Table.HeaderCell>
<Table.HeaderCell>POPO 가입일</Table.HeaderCell>
<Table.HeaderCell>POPO 유저타입</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
{
userStatusList.map((userStatus, idx) => { return (
<Table.Row key={userStatus.uuid} negative={userStatus.status === 'not_registered'}>
<Table.Cell>{idx + 1}</Table.Cell>
<Table.Cell>{userStatus.name}</Table.Cell>
<Table.Cell>{userStatus.email}</Table.Cell>
<Table.Cell>{userStatus.user_name}</Table.Cell>
<Table.Cell>{userStatus.created_at}</Table.Cell>
<Table.Cell>{userStatus.user_type}</Table.Cell>
</Table.Row>
)})
}
</Table.Body>
</Table>
)
}

export default RcUserTable
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"dependencies": {
"@nivo/bar": "^0.84.0",
"@nivo/core": "^0.84.0",
"axios": "^1.6.5",
"axios": "^1.6.7",
"moment": "^2.30.1",
"next": "^12.3.4",
"react": "^17.0.2",
Expand Down
61 changes: 47 additions & 14 deletions pages/board/rc-students-list.jsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,54 @@
import BoardLayout from '@/components/board/board.layout'
import { useEffect, useState } from 'react';
import { Button } from 'semantic-ui-react';

import { PoPoAxios } from '@/utils/axios.instance';
import BoardLayout from '@/components/board/board.layout'
import CsvUploadForm from '@/components/common/csv-upload.form';
import { Button } from 'semantic-ui-react';
import RcUserTable from '@/components/user/rc-user.table';

const RcStudentsListPage = ({ popoRcStdntCnt, totalRcStdntCnt }) => {
const [isLoaded, setIsLoaded] = useState(false);
const [rcStudentStatusList, setRcStudentStatusList] = useState([]);

useEffect(() => {
PoPoAxios.get('/setting/get-rc-students-status', { withCredentials: true })
.then((res) => {
setRcStudentStatusList(res.data);
setIsLoaded(true);
})
.catch((err) => {
alert(`RC 사생 명단을 불러오는데 실패했습니다.\n${err.response.data.message}`)
})
}, [popoRcStdntCnt, totalRcStdntCnt])

return (
<BoardLayout>
<h3>RC 사생 명단 업로드</h3>
<div>
RC 사생에게만 RC 장소 예약을 받기 위해 RC 사생 명단 정보가 필요합니다.
<p style={{lineHeight: '1.6em'}}>
RC 사생에게만 RC 장소 예약을 받기 위해 RC 사생 명단 정보가 필요합니다.<br/>
아래 주소에서 CSV 파일을 다운 받아 요 형식에 맞춰 입력 후, 다시 CSV 파일을 업로드 해주세요.
CSV 파일이 업로드 되면, RC 사생 명단 초기화 후 업로드 된 명단에 있는 Povis ID를 가진 모든 유저를 RC 사생으로 분류합니다.
만약 RC 사생 명단 업로드 후에 RC 사생이 추가로 가입한다면, 자동으로 RC 사생으로 분류됩니다.
</div>
<span style={{color: "red"}}>(name, email 컬럼은 필수 입니다.)</span><br/>
CSV 파일이 업로드 되면, RC 사생 명단 초기화(reset) 후 업로드 된 명단에 있는 Povis ID를 가진 모든 유저를 RC 사생으로 분류합니다.<br/>
만약 RC 사생 명단을 업로드 한 후에, RC 사생이 가입한다면 그때는 <strong>자동</strong>으로 RC 사생으로 분류됩니다.
</p>

<ul>
<li>
POPO 가입 RC 사생 수: {popoRcStdntCnt}명 ({Number((popoRcStdntCnt / totalRcStdntCnt * 100).toFixed(1))}%)
POPO 가입 RC 사생 수: {popoRcStdntCnt}명 ({Number((popoRcStdntCnt / totalRcStdntCnt * 100).toFixed(1))}%)
</li>
<li>
전체 RC 사생 수: {totalRcStdntCnt}
전체 RC 사생 수: {totalRcStdntCnt}
</li>
</ul>

<div style={{marginTop: 4, gap: 8}}>
<Button
size='tiny'
href={`${PoPoAxios.getUri()}/setting/download-rc-students-list`}
>
CSV 다운로드
RC 명단 다운로드
</Button>

<Button
size='tiny'
onClick={() => {
Expand All @@ -45,7 +63,7 @@ const RcStudentsListPage = ({ popoRcStdntCnt, totalRcStdntCnt }) => {
})
}}
>
RC 사생 명단 Sync
업로드한 RC 명단을 기준으로 다시 적용하기
</Button>
</div>

Expand All @@ -55,6 +73,21 @@ const RcStudentsListPage = ({ popoRcStdntCnt, totalRcStdntCnt }) => {
uploadUri={'/setting/rc-students-list'}
/>
</div>

<div style={{marginTop: 12}}>
{
isLoaded ? (
<>
<h3>RC 사생 명단</h3>
<RcUserTable
userStatusList={rcStudentStatusList}
/>
</>
) : (
<h3>RC 사생 명단 불러오는 중...</h3>
)
}
</div>
</BoardLayout>
)
}
Expand All @@ -64,7 +97,7 @@ export default RcStudentsListPage;
export async function getServerSideProps() {
const res1 = await PoPoAxios.get('/user/count/RC_STUDENT');
const popoRcStdntCnt = res1.data;

const res2 = await PoPoAxios.get('/setting/count-rc-students-list');
const totalRcStdntCnt = res2.data;

Expand Down
38 changes: 31 additions & 7 deletions pages/introduce/club/index.jsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,47 @@
import React from 'react'
import React, { useMemo, useState } from 'react'
import Link from "next/link";
import { Button } from 'semantic-ui-react'
import { Button, Select } from 'semantic-ui-react'

import IntroduceLayout from '@/components/introduce/introduce.layout'
import ClubTable from '@/components/introduce/club.table'
import { PoPoAxios } from '@/utils/axios.instance';
import { ClubTypeOptions } from '@/assets/club.type.options';

const SelectClubTypeOptions = [
{ key: 'ALL', value: 'ALL', text: '전체' },
...ClubTypeOptions,
]

const ClubIntroducePage = ({ clubList }) => {
const [selectedClubType, setSelectedClubType] = useState('ALL');

const filteredClubList = useMemo(() => {
if (selectedClubType === 'ALL') return clubList;
return clubList.filter(club => club.clubType === selectedClubType);

}, [selectedClubType, clubList])


return (
<IntroduceLayout>
<h3>동아리 소개글</h3>
<div style={{marginBottom: "1rem"}}>
<Link href={'/introduce/club/create'}>
<Button>동아리 생성</Button>
</Link>
<div style={{ marginBottom: '1rem', display: 'flex', justifyContent: 'space-between' }}>
<div style={{marginBottom: "1rem"}}>
<Link href={'/introduce/club/create'}>
<Button>동아리 생성</Button>
</Link>
</div>
<div>
<Select
value={selectedClubType}
options={SelectClubTypeOptions}
onChange={(e, { value }) => setSelectedClubType(value)}
/>
</div>
</div>
<div>
<ClubTable
clubs={clubList}
clubs={filteredClubList}
/>
</div>
</IntroduceLayout>
Expand Down
34 changes: 14 additions & 20 deletions pages/statistics/index.jsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,28 @@
import { useState } from "react";
import dynamic from 'next/dynamic';
import { Dropdown, List } from "semantic-ui-react";

import moment from 'moment'

import LayoutWithAuth from '@/components/layout/layout.auth.with'

// https://github.com/plouc/nivo/issues/1941
const NewUserBar = dynamic(() => import('../../components/statistics/new-user.bar'), { ssr: false })
const NewReservationBar = dynamic(() => import('../../components/statistics/new-reservation.bar'), { ssr: false })

const YearOptions = [
{
key: 2021,
text: '2021년',
value: 2021,
},
{
key: 2022,
text: '2022년',
value: 2022,
},
{
key: 2023,
text: '2023년',
value: 2023,
}
]

const StatisticsPage = () => {
const [year, setYear] = useState(2023);
const thisYear = moment().year();
const popoStartYear = 2021;

const [year, setYear] = useState(thisYear);

const YearOptions = Array.from(
{length: thisYear - popoStartYear + 1},
(v, k) => { return {
key: k + popoStartYear,
text: `${k + popoStartYear}년`,
value: k + popoStartYear
} }
);

return (
<LayoutWithAuth>
Expand Down

0 comments on commit be65a95

Please sign in to comment.