Skip to content

Commit f6e1f2e

Browse files
authored
User Detail Page (#89)
1 parent 20fb709 commit f6e1f2e

File tree

10 files changed

+365
-49
lines changed

10 files changed

+365
-49
lines changed

.github/workflows/github-action.yaml

+10-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
docker_build_and_push:
3131
name: Docker build and push
3232
needs: lint
33-
runs-on: ubuntu-latest
33+
runs-on: ubuntu-24.04-arm
3434
steps:
3535
- name: Checkout
3636
uses: actions/checkout@v4
@@ -71,14 +71,22 @@ jobs:
7171
cache-from: type=gha
7272
cache-to: type=gha,mode=max
7373
push: true
74+
provenance: false # Disable image index metadata
7475

7576
redeploy_dev_service:
7677
name: Redeploy Dev Service
7778
needs: docker_build_and_push
7879
runs-on: ubuntu-latest
7980
steps:
8081
- name: Redeploy Dev Service
81-
run: curl -X POST ${{ secrets.PORTAINER_DEV_SERVICE_WEBHOOK }}
82+
run: |
83+
RESPONSE=$(curl -s -o response.txt -w "%{http_code}" -X POST ${{ secrets.PORTAINER_DEV_SERVICE_WEBHOOK }})
84+
if [ "$RESPONSE" -ne 204 ]; then
85+
echo "❌ Deployment failed! HTTP Response: $RESPONSE"
86+
cat response.txt # 오류 메시지 출력 (필요 시)
87+
exit 1
88+
fi
89+
echo "✅ Deployment successful! HTTP Response: $RESPONSE"
8290
8391
deploy_health_check:
8492
name: Check Application Status

.pre-commit-config.yaml

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
repos:
22
- repo: local
33
hooks:
4-
- id: npm-run-lint
5-
name: Run ESLint
6-
entry: npm run lint
7-
language: system
8-
types: [javascript, jsx]
94
- id: npm-run-format
105
name: Run Prettier
116
entry: npm run format
127
language: system
13-
types: [javascript, jsx]
8+
types: [javascript, jsx, json, yaml]
9+
pass_filenames: true
10+
- id: npm-run-lint
11+
name: Run ESLint
12+
entry: npm run lint:file
13+
language: system
14+
types: [javascript, jsx, json, yaml]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import React from 'react';
2+
import { Label, Table } from 'semantic-ui-react';
3+
import moment from 'moment';
4+
5+
const EquipmentReservationTable2 = ({ reservations, startIdx }) => {
6+
return (
7+
<Table celled selectable textAlign={'center'}>
8+
<Table.Header>
9+
<Table.Row>
10+
<Table.HeaderCell width={1}>idx.</Table.HeaderCell>
11+
<Table.HeaderCell width={3}>장비 목록</Table.HeaderCell>
12+
<Table.HeaderCell>예약 제목</Table.HeaderCell>
13+
<Table.HeaderCell>예약 설명</Table.HeaderCell>
14+
<Table.HeaderCell width={4}>예약 기간</Table.HeaderCell>
15+
<Table.HeaderCell width={2}>상태</Table.HeaderCell>
16+
</Table.Row>
17+
</Table.Header>
18+
<Table.Body>
19+
{reservations.map((reservation, idx) => (
20+
<Table.Row key={reservation.uuid}>
21+
<Table.Cell>{startIdx + idx + 1}</Table.Cell>
22+
<Table.Cell>
23+
{reservation.equipments.map((equipment) => {
24+
return (
25+
<Label
26+
size={'tiny'}
27+
key={equipment.uuid}
28+
style={{ margin: '2px' }}
29+
>
30+
{equipment.name}
31+
</Label>
32+
);
33+
})}
34+
</Table.Cell>
35+
<Table.Cell>{reservation.title}</Table.Cell>
36+
<Table.Cell>{reservation.description}</Table.Cell>
37+
<Table.Cell>
38+
<b>
39+
{moment(reservation.date, 'YYYYMMDD').format(
40+
'YYYY년 MM월 DD일',
41+
)}
42+
<br />
43+
{moment(reservation.start_time, 'HHmm').format('HH:mm')}
44+
&nbsp;~&nbsp;
45+
{moment(reservation.end_time, 'HHmm').format('HH:mm')}
46+
</b>
47+
</Table.Cell>
48+
<Table.Cell>{reservation.status}</Table.Cell>
49+
</Table.Row>
50+
))}
51+
</Table.Body>
52+
</Table>
53+
);
54+
};
55+
56+
export default EquipmentReservationTable2;

components/navbar/menu.item.user.jsx

+8-3
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,14 @@ const MenuItemUser = () => {
3737
}}
3838
>
3939
<Dropdown.Item text={'로그아웃'} onClick={handleLogout} />
40-
<Dropdown.Item
41-
text={`popo-${process.env.NEXT_PUBLIC_POPO_VERSION}`}
42-
/>
40+
<a
41+
href={`https://github.com/PoApper/popo-admin-web/commits/${process.env.NEXT_PUBLIC_POPO_VERSION}`}
42+
target="_blank"
43+
>
44+
<Dropdown.Item
45+
text={`popo-${process.env.NEXT_PUBLIC_POPO_VERSION}`}
46+
/>
47+
</a>
4348
</Dropdown.Menu>
4449
</Dropdown>
4550
</Menu.Item>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import React from 'react';
2+
import { Table } from 'semantic-ui-react';
3+
import moment from 'moment';
4+
5+
const PlaceReservationTable2 = ({ reservations, startIdx }) => {
6+
return (
7+
<Table celled selectable textAlign={'center'}>
8+
<Table.Header>
9+
<Table.Row>
10+
<Table.HeaderCell width={1}>idx.</Table.HeaderCell>
11+
<Table.HeaderCell width={3}>장소명</Table.HeaderCell>
12+
<Table.HeaderCell>예약 제목</Table.HeaderCell>
13+
<Table.HeaderCell>예약 설명</Table.HeaderCell>
14+
<Table.HeaderCell width={4}>예약 기간</Table.HeaderCell>
15+
<Table.HeaderCell width={2}>상태</Table.HeaderCell>
16+
</Table.Row>
17+
</Table.Header>
18+
<Table.Body>
19+
{reservations.map((reservation, idx) => (
20+
<Table.Row key={reservation.uuid}>
21+
<Table.Cell>{startIdx + idx + 1}</Table.Cell>
22+
<Table.Cell>{reservation.place.name}</Table.Cell>
23+
<Table.Cell>{reservation.title}</Table.Cell>
24+
<Table.Cell>{reservation.description}</Table.Cell>
25+
<Table.Cell>
26+
<b>
27+
{moment(reservation.date, 'YYYYMMDD').format(
28+
'YYYY년 MM월 DD일',
29+
)}
30+
<br />
31+
{moment(reservation.start_time, 'HHmm').format('HH:mm')}
32+
&nbsp;~&nbsp;
33+
{moment(reservation.end_time, 'HHmm').format('HH:mm')}
34+
</b>
35+
</Table.Cell>
36+
<Table.Cell>{reservation.status}</Table.Cell>
37+
</Table.Row>
38+
))}
39+
</Table.Body>
40+
</Table>
41+
);
42+
};
43+
44+
export default PlaceReservationTable2;

components/user/user.table.jsx

+19-19
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { Table } from 'semantic-ui-react';
1+
import { Table, Icon } from 'semantic-ui-react';
2+
import Link from 'next/link';
23
import moment from 'moment';
3-
import UserUpdateModal from './user.update.modal';
44

55
const userTypes = {
66
STUDENT: '학생',
@@ -23,28 +23,28 @@ const UserTable = ({ users, startIdx }) => {
2323
<Table.HeaderCell>유저 타입</Table.HeaderCell>
2424
<Table.HeaderCell>가입일</Table.HeaderCell>
2525
<Table.HeaderCell>마지막 로그인</Table.HeaderCell>
26+
<Table.HeaderCell></Table.HeaderCell>
2627
</Table.Row>
2728
</Table.Header>
2829
<Table.Body>
2930
{users.map((user, idx) => {
3031
return (
31-
<UserUpdateModal
32-
key={user.uuid}
33-
user={user}
34-
trigger={
35-
<Table.Row key={user.uuid}>
36-
<Table.Cell>{startIdx + idx + 1}</Table.Cell>
37-
<Table.Cell>{user.name}</Table.Cell>
38-
<Table.Cell>{userTypes[user.userType]}</Table.Cell>
39-
<Table.Cell>
40-
{moment(user.createdAt).format('YYYY-MM-DD HH:mm')}
41-
</Table.Cell>
42-
<Table.Cell>
43-
{moment(user.lastLoginAt).format('YYYY-MM-DD HH:mm')}
44-
</Table.Cell>
45-
</Table.Row>
46-
}
47-
/>
32+
<Table.Row key={user.uuid}>
33+
<Table.Cell>{startIdx + idx + 1}</Table.Cell>
34+
<Table.Cell>{user.name}</Table.Cell>
35+
<Table.Cell>{userTypes[user.userType]}</Table.Cell>
36+
<Table.Cell>
37+
{moment(user.createdAt).format('YYYY-MM-DD HH:mm')}
38+
</Table.Cell>
39+
<Table.Cell>
40+
{moment(user.lastLoginAt).format('YYYY-MM-DD HH:mm')}
41+
</Table.Cell>
42+
<Table.Cell>
43+
<Link href={`user/${user.uuid}`}>
44+
<Icon name={'edit'} />
45+
</Link>
46+
</Table.Cell>
47+
</Table.Row>
4848
);
4949
})}
5050
</Table.Body>

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
"start": "next start -p 3001",
99
"format:check": "prettier --c .",
1010
"format": "prettier --w .",
11-
"lint": "next lint"
11+
"lint": "next lint",
12+
"lint:file": "next lint --file"
1213
},
1314
"dependencies": {
1415
"@nivo/bar": "^0.87.0",

pages/place/reservation/create.jsx

+9-18
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ const PlaceReservationCreatePage = ({ placeList }) => {
3838

3939
const [placeInfo, setPlaceInfo] = useState(null);
4040
const [userInfo, setUserInfo] = useState(null);
41-
console.log(placeInfo);
4241

4342
const [phone, setPhone] = useState('');
4443
const [title, setTitle] = useState('');
@@ -70,13 +69,6 @@ const PlaceReservationCreatePage = ({ placeList }) => {
7069
}, [router]);
7170

7271
function handleSubmit() {
73-
if (!isPossible) {
74-
alert(
75-
`예약이 불가능한 시간대입니다. ${placeInfo.name}의 사용 가능 시간을 확인해주세요.`,
76-
);
77-
return;
78-
}
79-
8072
if (title.length == 1 || description.length == 1) {
8173
alert('예약 설명이 너무 짤습니다.');
8274
return;
@@ -174,13 +166,6 @@ const PlaceReservationCreatePage = ({ placeList }) => {
174166
/>
175167
</Form.Group>
176168

177-
{isPossible ? null : (
178-
<Message negative>
179-
예약이 불가능한 시간대입니다. {placeInfo.name}의 사용 가능
180-
시간을 확인해주세요.
181-
</Message>
182-
)}
183-
184169
<div className={'field'} style={{ maxWidth: 240 }}>
185170
<label>사용 가능 시간</label>
186171
<div style={{ color: 'gray' }}>
@@ -200,9 +185,15 @@ const PlaceReservationCreatePage = ({ placeList }) => {
200185
</p>
201186
</Message>
202187

203-
<Form.Button onClick={handleSubmit} disabled={!isPossible}>
204-
생성
205-
</Form.Button>
188+
{!isPossible ? (
189+
<Message negative>
190+
선택하신 시간 대는 예약이 <b>불가능한</b> 시간대로 설정 되어
191+
있습니다. 다만, 관리자 화면에서는 강제로 {placeInfo.name}에 대한
192+
예약을 진행할 수 있습니다. 계속 진행하시겠습니까?
193+
</Message>
194+
) : null}
195+
196+
<Form.Button onClick={handleSubmit}>생성</Form.Button>
206197
</>
207198
) : null}
208199
</Form>

0 commit comments

Comments
 (0)