Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

予算管理ページの作成(フロント) #894

Open
wants to merge 12 commits into
base: develop
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
import { useState } from 'react';
import { Card, EditButton, AddButton, Title } from '@/components/common';
import PrimaryButton from '@/components/common/OutlinePrimaryButton/OutlinePrimaryButton';

interface RegistrationItem {
id: string;
name: string;
budget?: number;
used?: number;
remaining?: number;
}

interface Department {
id: string;
name: string;
budget: number;
used: number;
remaining: number;
}

interface Division {
id: string;
name: string;
departmentId: string;
budget: number;
used: number;
remaining: number;
}

interface Item {
id: string;
name: string;
divisionId: string;
budget: number;
used: number;
remaining: number;
}

interface BudgetManagementProps {
departments: Department[];
divisions: Division[];
items: Item[];
}

export default function BudgetManagement({ departments, divisions, items }: BudgetManagementProps) {
const [selectedDepartmentId, setSelectedDepartmentId] = useState('');
const [selectedDivisionId, setSelectedDivisionId] = useState('');

const handleDepartmentChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setSelectedDepartmentId(e.target.value);
setSelectedDivisionId('');
};

const handleDivisionChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setSelectedDivisionId(e.target.value);
};

let displayItems: RegistrationItem[] = [];
let title = '購入報告';
const showBudgetColumns = true;

if (selectedDivisionId) {
displayItems = items.filter((item) => item.divisionId === selectedDivisionId);
title = '申請物品';
} else if (selectedDepartmentId) {
displayItems = divisions.filter((div) => div.departmentId === selectedDepartmentId);
title = '申請部門';
} else {
displayItems = departments;
title = '申請局';
}

const totalBudget = displayItems.reduce((sum, item) => sum + (item.budget || 0), 0);
const totalUsed = displayItems.reduce((sum, item) => sum + (item.used || 0), 0);
const totalRemaining = displayItems.reduce((sum, item) => sum + (item.remaining || 0), 0);

return (
<Card>
<div className='px-4 py-10'>
<div className='flex-start mb-4 flex'>
<Title>予算管理ページ</Title>
</div>
<div className='mb-4 flex flex-col items-center md:flex-row md:justify-between'>
<div className='flex flex-col gap-4'>
<div className='flex gap-3'>
<span className='text-base font-light'>申請する局</span>
<select
value={selectedDepartmentId}
onChange={handleDepartmentChange}
className='border-b border-black-300 focus:outline-none'
>
<option value=''>ALL</option>
{departments.map((dept) => (
<option key={dept.id} value={dept.id}>
{dept.name}
</option>
))}
</select>
</div>
<div className={`flex gap-3 ${selectedDepartmentId ? 'visible' : 'invisible'}`}>
<span className='text-base font-light'>申請する部門</span>
<select
value={selectedDivisionId}
onChange={handleDivisionChange}
className='border-b border-black-300 focus:outline-none'
>
<option value=''>ALL</option>
{divisions
.filter((div) => div.departmentId === selectedDepartmentId)
.map((div) => (
<option key={div.id} value={div.id}>
{div.name}
</option>
))}
</select>
</div>
</div>
<div className='w-full md:w-fit flex flex-col gap-1 md:flex-row md:gap-3 mt-2'>
<PrimaryButton className='w-full md:w-fit'>CSVダウンロード</PrimaryButton>
<AddButton className='w-full md:w-fit'>{title}登録</AddButton>
</div>
</div>
<div className='mt-5 overflow-x-auto'>
<table className='w-full table-auto border-collapse'>
<thead>
<tr className='border border-x-white-0 border-b-primary-1 border-t-white-0 py-3'>
<th className='w-1/4 pb-2 text-center font-medium text-black-600'>{title}</th>
{showBudgetColumns && (
<>
<th className='w-1/4 pb-2 text-center font-medium text-black-600'>予算</th>
<th className='w-1/4 pb-2 text-center font-medium text-black-600'>使用額</th>
<th className='w-1/4 pb-2 text-center font-medium text-black-600'>残高</th>
</>
)}
</tr>
</thead>
<tbody>
{displayItems.map((item, index) => (
<tr key={item.id} className={index !== displayItems.length - 1 ? 'border-b' : ''}>
<td className='py-3'>
<div className='text-center text-sm text-black-600'>
<div className='flex items-center justify-center gap-2'>
<span className='text-nowrap text-primary-1 underline'>{item.name}</span>
<EditButton onClick={() => console.log('Edit clicked:', item.id)} />
</div>
</div>
</td>
{showBudgetColumns && (
<>
<td className='py-3'>
<div className='text-center text-sm text-black-600'>
{item.budget?.toLocaleString() || '-'}
</div>
</td>
<td className='py-3'>
<div className='text-center text-sm text-black-600'>
{item.used?.toLocaleString() || '-'}
</div>
</td>
<td className='py-3'>
<div className='text-center text-sm text-black-600'>
{item.remaining?.toLocaleString() || '-'}
</div>
</td>
</>
)}
</tr>
))}
{showBudgetColumns && displayItems.length > 0 && (
<tr className='border border-x-white-0 border-b-white-0 border-t-primary-1'>
<td className='py-3'>
<div className='text-center text-sm text-black-600'>合計</div>
</td>
<td className='py-3'>
<div className='text-center text-sm text-black-600'>
{totalBudget.toLocaleString()}
</div>
</td>
<td className='py-3'>
<div className='text-center text-sm text-black-600'>
{totalUsed.toLocaleString()}
</div>
</td>
<td className='py-3'>
<div className='text-center text-sm text-black-600'>
{totalRemaining.toLocaleString()}
</div>
</td>
</tr>
)}
{displayItems.length === 0 && (
<tr>
<td
colSpan={showBudgetColumns ? 4 : 1}
className='text-gray-500 px-4 py-6 text-center text-sm'
>
データがありません
</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
</Card>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface Props {

function PrimaryButton(props: Props): JSX.Element {
const className =
'px-4 py-2 text-primary-1 font-bold text-md rounded-lg bg-white-0 border border-primary-1 hover:bg-white-100 hover:text-primary-2 hover:border-primary-2' +
'flex justify-center px-4 py-2 text-primary-1 font-bold text-md rounded-lg bg-white-0 border border-primary-1 hover:bg-white-100 hover:text-primary-2 hover:border-primary-2' +
(props.className ? ` ${props.className}` : '');
return (
<button className={clsx(className)} onClick={props.onClick}>
Expand Down
5 changes: 5 additions & 0 deletions view/next-project/src/constants/linkItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ export const FinanceLinkItems: LinkItemProps[] = [
icon: <HiCurrencyDollar className='mx-2 text-xl' />,
href: '/budgets',
},
{
name: '予算管理',
icon: <HiCurrencyDollar className='mx-2 text-xl' />,
href: '/budget_managements',
},
{
name: '学内募金',
icon: <MdOutlineSavings className='mx-2 text-xl' />,
Expand Down
30 changes: 30 additions & 0 deletions view/next-project/src/pages/budget_managements/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import BudgetManagement from '@/components/budget_managements/BudgetManagement';
import MainLayout from '@/components/layout/MainLayout';

export default function Home() {
const departments = [
{ id: '1', name: '制作局', budget: 20000, used: 5000, remaining: 15000 },
{ id: '2', name: '渉外局', budget: 18000, used: 4000, remaining: 14000 },
{ id: '3', name: '企画局', budget: 22000, used: 6000, remaining: 16000 },
{ id: '4', name: '財務局', budget: 25000, used: 5500, remaining: 19500 },
{ id: '5', name: '情報局', budget: 21000, used: 7000, remaining: 14000 },
];

const divisions = [
{ id: '1', name: '制作部門A', departmentId: '1', budget: 10000, used: 3000, remaining: 7000 },
{ id: '2', name: '制作部門B', departmentId: '1', budget: 10000, used: 2000, remaining: 8000 },
{ id: '3', name: '渉外部門A', departmentId: '2', budget: 9000, used: 4000, remaining: 5000 },
];

const items = [
{ id: '1', name: '物品A', divisionId: '1', budget: 5000, used: 1000, remaining: 4000 },
{ id: '2', name: '物品B', divisionId: '1', budget: 5000, used: 500, remaining: 4500 },
{ id: '3', name: '物品C', divisionId: '2', budget: 6000, used: 1500, remaining: 4500 },
];

return (
<MainLayout>
<BudgetManagement departments={departments} divisions={divisions} items={items} />
</MainLayout>
);
}
Loading