Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions client/src/app/admin/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import AttendanceChart from "@/app/admin/AttendanceChart"

interface DashboardData {
totalUsers: number
communityUsers: number
totalCommunities: number
statistics: {
weekly: {
Expand Down Expand Up @@ -64,6 +65,11 @@ interface DashboardData {
date: string
memo: string
}>
villagesWithoutAttendance: Array<{
leader: { id: string; name: string }
villageId: number
villageName: string
}>
lastUpdated: string
}

Expand Down Expand Up @@ -179,6 +185,26 @@ function index() {
</Typography>
<Typography variant="body2" color="text.secondary">
등록된 인원
<br />
(장결 포함)
</Typography>
</Stack>
</Stack>
</CardContent>
</Card>

<Card sx={{ flex: 1 }}>
<CardContent>
<Stack direction="row" alignItems="center" spacing={2}>
<PeopleIcon sx={{ fontSize: 40, color: "#1976d2" }} />
<Stack>
<Typography variant="h4" fontWeight="bold">
{dashboardData.communityUsers}
</Typography>
<Typography variant="body2" color="text.secondary">
등록된 인원
<br />
(장결 재외)
</Typography>
</Stack>
</Stack>
Expand Down Expand Up @@ -235,6 +261,46 @@ function index() {
</Stack>

<Stack direction={{ xs: "column", md: "row" }} spacing={3}>
<Box
sx={{
width: { xs: "100%", md: 180 },
flexShrink: 0,
pt: { xs: 0, md: 2 },
}}
>
<Typography textAlign="center" variant="subtitle2" gutterBottom>
출석 미등록 마을
</Typography>
<Stack
width="100%"
direction="row"
gap="4px"
overflow="none"
display="flex"
flexWrap="wrap"
>
{dashboardData.villagesWithoutAttendance.map((village) => (
<Stack
bgcolor="white"
key={village.villageId}
border={1}
borderColor="divider"
p={1}
borderRadius="8px"
>
<Typography variant="body2" noWrap>
{village.villageName}
</Typography>
</Stack>
))}
</Stack>
{dashboardData.villagesWithoutAttendance.length === 0 && (
<Typography variant="caption" color="text.secondary">
없음
</Typography>
)}
</Box>

<Card sx={{ flex: 1 }}>
<CardContent>
<Typography variant="h6" fontWeight="bold" gutterBottom>
Expand Down
186 changes: 95 additions & 91 deletions client/src/app/leader/newcomer/management/NewcomerFilter.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box, Button, MenuItem, Stack, TextField } from "@mui/material"
import { Box, Button, MenuItem, Select, Stack, TextField } from "@mui/material"

interface NewcomerFilterProps {
filterName: string
Expand Down Expand Up @@ -36,15 +36,102 @@ export default function NewcomerFilter({
bgcolor="#fafafa"
boxShadow="0 2px 4px rgba(0,0,0,0.1)"
>
<Stack
direction="row"
alignItems="center"
justifyContent="space-between"
mb="16px"
>
<Stack direction="row" alignItems="center" justifyContent="space-between">
<Box fontWeight="bold" fontSize="16px" color="#333">
필터
조회 조건
</Box>

<Stack
flex={1}
gap="12px"
direction="row"
justifyContent="flex-start"
alignItems="center"
borderLeft="1px solid #aaa"
mx="24px"
pl="12px"
>
<Stack direction="row" alignItems="center" gap="12px">
<Box width="32px" fontSize="14px" textAlign="right">
이름:
</Box>
<TextField
size="small"
placeholder="이름 검색"
value={filterName}
onChange={(e) => setFilterName(e.target.value)}
variant="outlined"
sx={{ flex: 1 }}
/>
</Stack>

<Stack direction="row" alignItems="center" gap="12px">
<Box width="32px" fontSize="14px" textAlign="right">
성별:
</Box>
<Select
size="small"
value={filterGender}
onChange={(e) =>
setFilterGender(e.target.value as "" | "man" | "woman")
}
variant="outlined"
sx={{ flex: 1 }}
displayEmpty
>
<MenuItem value="">전체</MenuItem>
<MenuItem value="man">남</MenuItem>
<MenuItem value="woman">여</MenuItem>
</Select>
</Stack>

<Stack direction="row" alignItems="center" gap="12px">
<Box width="32px" fontSize="14px" textAlign="right">
상태:
</Box>
<Select
size="small"
value={filterStatus}
onChange={(e) => setFilterStatus(e.target.value)}
variant="outlined"
sx={{ flex: 1 }}
displayEmpty
>
<MenuItem value="">전체</MenuItem>
<MenuItem value="NORMAL">활동중</MenuItem>
<MenuItem value="PROMOTED">등반</MenuItem>
<MenuItem value="PENDING">보류</MenuItem>
<MenuItem value="DELETED">삭제</MenuItem>
</Select>
</Stack>

<Stack direction="row" alignItems="center" gap="12px">
<Box width="32px" fontSize="14px" textAlign="right">
생년:
</Box>
<TextField
size="small"
placeholder="최소"
value={filterMinYear}
onChange={(e) => setFilterMinYear(e.target.value)}
variant="outlined"
type="number"
sx={{ width: "90px" }}
/>
<Box fontSize="12px" color="gray">
~
</Box>
<TextField
size="small"
placeholder="최대"
value={filterMaxYear}
onChange={(e) => setFilterMaxYear(e.target.value)}
variant="outlined"
type="number"
sx={{ width: "90px" }}
/>
</Stack>
</Stack>
<Button
size="small"
onClick={clearFilters}
Expand All @@ -58,89 +145,6 @@ export default function NewcomerFilter({
초기화
</Button>
</Stack>

<Stack gap="12px">
<Stack direction="row" alignItems="center" gap="12px">
<Box width="60px" fontSize="14px">
이름:
</Box>
<TextField
size="small"
placeholder="이름 검색"
value={filterName}
onChange={(e) => setFilterName(e.target.value)}
variant="outlined"
sx={{ flex: 1 }}
/>
</Stack>

<Stack direction="row" alignItems="center" gap="12px">
<Box width="60px" fontSize="14px">
성별:
</Box>
<TextField
select
size="small"
value={filterGender}
onChange={(e) =>
setFilterGender(e.target.value as "" | "man" | "woman")
}
variant="outlined"
sx={{ flex: 1 }}
>
<MenuItem value="">전체</MenuItem>
<MenuItem value="man">남</MenuItem>
<MenuItem value="woman">여</MenuItem>
</TextField>
</Stack>

<Stack direction="row" alignItems="center" gap="12px">
<Box width="60px" fontSize="14px">
상태:
</Box>
<TextField
select
size="small"
value={filterStatus}
onChange={(e) => setFilterStatus(e.target.value)}
variant="outlined"
sx={{ flex: 1 }}
>
<MenuItem value="">전체</MenuItem>
<MenuItem value="NORMAL">활동중</MenuItem>
<MenuItem value="PROMOTED">등반</MenuItem>
<MenuItem value="PENDING">보류</MenuItem>
<MenuItem value="DELETED">삭제</MenuItem>
</TextField>
</Stack>

<Stack direction="row" alignItems="center" gap="12px">
<Box width="60px" fontSize="14px">
생년:
</Box>
<TextField
size="small"
placeholder="최소"
value={filterMinYear}
onChange={(e) => setFilterMinYear(e.target.value)}
variant="outlined"
type="number"
sx={{ width: "90px" }}
/>
<Box fontSize="12px" color="gray">
~
</Box>
<TextField
size="small"
placeholder="최대"
value={filterMaxYear}
onChange={(e) => setFilterMaxYear(e.target.value)}
variant="outlined"
type="number"
sx={{ width: "90px" }}
/>
</Stack>
</Stack>
</Stack>
)
}
2 changes: 1 addition & 1 deletion client/src/app/leader/newcomer/management/NewcomerForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export default function NewcomerForm({
flex={1}
gap="12px"
p="16px"
m="12px"
fontSize="14px"
border="1px solid #e0e0e0"
borderRadius="12px"
bgcolor="#ffffff"
Expand Down
3 changes: 2 additions & 1 deletion client/src/app/leader/newcomer/management/NewcomerTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ export default function NewcomerTable({
width="50%"
flex={1}
border="1px solid #ccc"
maxHeight="calc(100vh - 100px)"
borderRadius="8px"
maxHeight="calc(100vh - 230px)"
overflow="auto"
>
<Box p="8px" bgcolor="#f5f5f5" fontSize="14px">
Expand Down
28 changes: 14 additions & 14 deletions client/src/app/leader/newcomer/management/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,20 @@ export default function NewcomerManagement() {

return (
<Stack>
<Stack direction="row" p="12px" gap="12px">
<NewcomerFilter
filterName={filterName}
setFilterName={setFilterName}
filterGender={filterGender}
setFilterGender={setFilterGender}
filterMinYear={filterMinYear}
setFilterMinYear={setFilterMinYear}
filterMaxYear={filterMaxYear}
setFilterMaxYear={setFilterMaxYear}
filterStatus={filterStatus}
setFilterStatus={setFilterStatus}
clearFilters={clearFilters}
/>
<Stack direction="row" px="12px" gap="12px">
<NewcomerTable
newcomerList={newcomerList}
filteredNewcomerList={filteredNewcomers}
Expand All @@ -335,19 +348,6 @@ export default function NewcomerManagement() {
onNewcomerSelect={setSelectedNewcomer}
/>
<Stack width="40%">
<NewcomerFilter
filterName={filterName}
setFilterName={setFilterName}
filterGender={filterGender}
setFilterGender={setFilterGender}
filterMinYear={filterMinYear}
setFilterMinYear={setFilterMinYear}
filterMaxYear={filterMaxYear}
setFilterMaxYear={setFilterMaxYear}
filterStatus={filterStatus}
setFilterStatus={setFilterStatus}
clearFilters={clearFilters}
/>
<NewcomerForm
selectedNewcomer={selectedNewcomer}
onDataChange={onChangeData}
Expand Down
2 changes: 2 additions & 0 deletions client/src/components/Header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export default function Header() {
path: "/leader/attendance",
type: "menu",
})
/*
DrawerItems.push({
title: "순원 수련회 접수 조회",
icon: <HowToRegIcon fontSize="small" sx={{ color: "#667eea" }} />,
Expand All @@ -90,6 +91,7 @@ export default function Header() {
path: "/leader/retreat-attendance-for-same-age",
type: "menu",
})
*/

if (authUserData?.role.VillageLeader) {
DrawerItems.push({
Expand Down
8 changes: 8 additions & 0 deletions server/src/entity/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ export enum PermissionType {
retreatEditTeamScore = "retreatEditTeamScore",
retreatDeleteUser = "retreatDeleteUser",
retreatMediaManage = "retreatMediaManage",

// 새가족 관련 권한
MANAGE_NEWCOMER_INFORMATION = "MANAGE_NEWCOMER_INFORMATION",
MANAGE_NEWCOMER_EDUCATION = "MANAGE_NEWCOMER_EDUCATION",
}

export function permissionTypeToString(
Expand Down Expand Up @@ -68,6 +72,10 @@ export function permissionTypeToString(
return "수련회 참가자 삭제"
case PermissionType.retreatMediaManage:
return "수련회 미디어 관리"
case PermissionType.MANAGE_NEWCOMER_INFORMATION:
return "새가족 정보 관리"
case PermissionType.MANAGE_NEWCOMER_EDUCATION:
return "새가족 교육 관리"
default:
return "기타"
}
Expand Down
Loading
Loading