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
1 change: 1 addition & 0 deletions frontend
Submodule frontend added at 0c26d8
5 changes: 5 additions & 0 deletions next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ const nextConfig = {

return config;
},
images: {
domains: ['github.com'],
dangerouslyAllowSVG: true,
contentSecurityPolicy: "default-src 'self'; img-src 'self' data: https:;",
},
};

export default nextConfig;
75 changes: 75 additions & 0 deletions src/app/mobile/admin/dashboard/_components/DashboardItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import Image from 'next/image';
import convertTime from '@/utils/convertTime';

interface DashboardItemProps {
itemName: string;
imageUrl: string;
renterName: string;
studentId: number;
status: string;
applicatedAt: string;
}

export default function DashboardItem({
itemName,
imageUrl,
renterName,
studentId,
status,
applicatedAt,
}: DashboardItemProps) {
const RentalBtnText: Record<string, string> = {
PENDING: '대여',
RETURN_PENDING: '반납',
};

const applicatedTime = convertTime(applicatedAt);

return (
<section className="flex w-full items-center justify-between px-5 py-4">
<section className="flex items-center gap-4">
<section className="flex h-10 w-10 items-center justify-center rounded-full bg-gray-tertiary p-2.5">
<Image src={imageUrl} width={24} height={24} alt="물품 아이콘" />
</section>

<section className="flex flex-col gap-2">
<div className="text-sm font-semibold">{itemName}</div>

<section className="flex flex-col text-[10px] font-normal">
<section className="flex gap-1">
<div className="flex w-10">신청자</div>
<div className="">
{studentId} {renterName}
</div>
</section>

<section className="flex gap-1">
<div className="flex w-10">신청 시간</div>
<div className="">
{applicatedTime.formattedDate} {applicatedTime.formattedTime}
</div>
</section>
</section>
</section>
</section>

<section className="flex gap-2.5 text-sm font-semibold">
{/* TODO : API 보고 onClick 연결하기 */}
<button
type="button"
onClick={() => console.log('수락!')}
className="text-return-blue"
>
{RentalBtnText[status]} 승인
</button>
<button
type="button"
onClick={() => console.log('취소!')}
className="text-return-red"
>
{RentalBtnText[status]} 취소
</button>
</section>
</section>
);
}
104 changes: 104 additions & 0 deletions src/app/mobile/admin/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
'use client';

import { useState } from 'react';
import MobileLayout from '@/components/mobile/layout';
import Header from '@/components/mobile/Header';
import Dropdown from '@/components/mobile/Dropdown';
import useDropdown from '@/hooks/useDropdown';
import IconArrow from 'public/assets/icon-arrow.svg';
import { cn } from '@/lib/utils';
import DashboardItem from './_components/DashboardItem';

const RentalApplicationDetail = [
{
id: 0,
itemName: '우산',
imageUrl:
'https://github.com/user-attachments/assets/1b8c9ae9-a840-4756-a87d-c092958a2854',
renterName: '윤신지',
studentId: 20213102,
status: 'PENDING',
applicatedAt: '2025-02-16T08:44:45.476Z',
},
{
id: 1,
itemName: '타이레놀',
imageUrl:
'https://github.com/user-attachments/assets/159ee697-5a2e-43c8-a5a0-8ab73ae869fd',
renterName: '황현진',
studentId: 20213102,
status: 'RETURN_PENDING',
applicatedAt: '2025-02-13T08:44:45.476Z',
},
];

export default function Dashboard() {
const RentalFilterText: Record<string, string> = {
ALL: '전체',
PENDING: '대여 신청',
RETURN_PENDING: '반납 신청',
};

const [filter, setFilter] = useState('ALL');

const { showDropdown, hideDropdown, isDropdownVisible } = useDropdown();

const handleDropdown = () => {
return isDropdownVisible ? hideDropdown() : showDropdown();
};

const handleFilter = (filterText: string) => {
setFilter(filterText);
// 여기에 필터링 GET 쏘는 API 추가
};

const dropdownActions = [
{ title: '전체', func: () => handleFilter('ALL') },
{ title: '대여 신청', func: () => handleFilter('PENDING') },
{ title: '반납 신청', func: () => handleFilter('RETURN_PENDING') },
];

return (
<MobileLayout>
<Header title="관리자 대시보드" />

<section className="itmes-center mt-2.5 flex w-full justify-between px-5">
<div className="flex justify-between text-lg font-semibold">
신청 내역
</div>
<button
type="button"
onClick={isDropdownVisible ? undefined : handleDropdown}
className={`flex items-center gap-2.5 ${isDropdownVisible && 'pointer-events-none'}`}
>
<div className="flex text-sm font-semibold">
{RentalFilterText[filter]}
</div>
<IconArrow
className={
(cn('flex'), isDropdownVisible ? 'rotate-90' : '-rotate-90')
}
/>
</button>
</section>
{RentalApplicationDetail.map((item) => (
<DashboardItem
key={item.id}
itemName={item.itemName}
imageUrl={item.imageUrl}
renterName={item.renterName}
studentId={item.studentId}
status={item.status}
applicatedAt={item.applicatedAt}
/>
))}

<Dropdown
actions={dropdownActions}
isVisible={isDropdownVisible}
hideDropdown={hideDropdown}
positionClasses="top-15 right-5"
/>
</MobileLayout>
);
}
14 changes: 14 additions & 0 deletions src/utils/convertTime.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const convertTime = (date: string) => {
const TIME_ZONE = 9 * 60 * 60 * 1000;
const dateObj = new Date(date);

const formattedDate = new Date(dateObj.getTime() + TIME_ZONE)
.toISOString()
.split('T')[0];

const formattedTime = dateObj.toTimeString().split(' ')[0];

return { formattedDate, formattedTime };
};

export default convertTime;