Skip to content

Commit

Permalink
[fix] モックの作成とコンポーネントへのリファクタリング
Browse files Browse the repository at this point in the history
  • Loading branch information
TkymHrt committed Dec 2, 2024
1 parent 76edb82 commit e94e015
Show file tree
Hide file tree
Showing 2 changed files with 217 additions and 98 deletions.
215 changes: 117 additions & 98 deletions view/next-project/src/components/budget_managements/BudgetManagement.tsx
Original file line number Diff line number Diff line change
@@ -1,69 +1,93 @@
import { useState } from 'react';
import { useRouter } from 'next/router';
import { useState, useEffect } from 'react';
import {
Department,
Division,
Item,
fetchDepartments,
fetchDivisions,
fetchItems,
} from './mockApi';
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;
}
export default function BudgetManagement() {
const router = useRouter();
const { departmentId, divisionId } = router.query;

interface Department {
id: string;
name: string;
budget: number;
used: number;
remaining: number;
}
const [departments, setDepartments] = useState<Department[]>([]);
const [divisions, setDivisions] = useState<Division[]>([]);
const [items, setItems] = useState<Item[]>([]);

interface Division {
id: string;
name: string;
departmentId: string;
budget: number;
used: number;
remaining: number;
}
const [selectedDepartmentId, setSelectedDepartmentId] = useState(departmentId || '');
const [selectedDivisionId, setSelectedDivisionId] = useState(divisionId || '');

interface Item {
id: string;
name: string;
divisionId: string;
budget: number;
used: number;
remaining: number;
}
useEffect(() => {
fetchDepartments().then(setDepartments);
}, []);

interface BudgetManagementProps {
departments: Department[];
divisions: Division[];
items: Item[];
}
useEffect(() => {
setSelectedDepartmentId(departmentId || '');
}, [departmentId]);

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

const handleDepartmentChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setSelectedDepartmentId(e.target.value);
setSelectedDivisionId('');
};
useEffect(() => {
if (selectedDepartmentId) {
fetchDivisions(Number(selectedDepartmentId)).then(setDivisions);
setItems([]);
} else {
setDivisions([]);
setSelectedDivisionId('');
setItems([]);
}

const handleDivisionChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setSelectedDivisionId(e.target.value);
};
router.push(
{
pathname: router.pathname,
query: {
...router.query,
departmentId: selectedDepartmentId || undefined,
divisionId: undefined,
},
},
undefined,
{ shallow: true },
);
}, [selectedDepartmentId]);

useEffect(() => {
if (selectedDivisionId) {
fetchItems(Number(selectedDivisionId)).then(setItems);
} else {
setItems([]);
}

router.push(
{
pathname: router.pathname,
query: {
...router.query,
departmentId: selectedDepartmentId || undefined,
divisionId: selectedDivisionId || undefined,
},
},
undefined,
{ shallow: true },
);
}, [selectedDivisionId]);

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

if (selectedDivisionId) {
displayItems = items.filter((item) => item.divisionId === selectedDivisionId);
displayItems = items;
title = '申請物品';
} else if (selectedDepartmentId) {
displayItems = divisions.filter((div) => div.departmentId === selectedDepartmentId);
displayItems = divisions;
title = '申請部門';
} else {
displayItems = departments;
Expand All @@ -74,6 +98,26 @@ export default function BudgetManagement({ departments, divisions, items }: Budg
const totalUsed = displayItems.reduce((sum, item) => sum + (item.used || 0), 0);
const totalRemaining = displayItems.reduce((sum, item) => sum + (item.remaining || 0), 0);

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

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

const handleRowClick = (item: any) => {
if (!selectedDepartmentId) {
setSelectedDepartmentId(item.id);
setSelectedDivisionId('');
} else if (!selectedDivisionId) {
setSelectedDivisionId(item.id);
}
};

return (
<Card>
<div className='px-4 py-10'>
Expand Down Expand Up @@ -105,13 +149,11 @@ export default function BudgetManagement({ departments, divisions, items }: Budg
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>
))}
{divisions.map((div) => (
<option key={div.id} value={div.id}>
{div.name}
</option>
))}
</select>
</div>
</div>
Expand All @@ -136,56 +178,33 @@ export default function BudgetManagement({ departments, divisions, items }: Budg
</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>
<tr
key={item.id}
className={`cursor-pointer ${
index !== displayItems.length - 1 ? 'border-b' : ''
}`}
onClick={() => handleRowClick(item)}
>
<div className='flex justify-center gap-2 py-3'>
<td className='text-center text-primary-1 underline'>{item.name}</td>
<EditButton />
</div>

{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>
<td className='py-3 text-center'>{item.budget}</td>
<td className='py-3 text-center'>{item.used}</td>
<td className='py-3 text-center'>{item.remaining}</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>
<td className='py-3 text-center font-bold'>合計</td>
<td className='py-3 text-center font-bold'>{totalBudget}</td>
<td className='py-3 text-center font-bold'>{totalUsed}</td>
<td className='py-3 text-center font-bold'>{totalRemaining}</td>
</tr>
)}
{displayItems.length === 0 && (
Expand Down
100 changes: 100 additions & 0 deletions view/next-project/src/components/budget_managements/mockApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
export interface Department {
id: number;
name: string;
budget: number;
used: number;
remaining: number;
}

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

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

const departments: Department[] = [
{ 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 },
{ id: 6, name: '総務局', budget: 23000, used: 4500, remaining: 18500 },
];

const divisions: Division[] = [
{ 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 },
{ id: 4, name: '渉外部門B', departmentId: 2, budget: 9000, used: 0, remaining: 9000 },
{ id: 5, name: '企画部門A', departmentId: 3, budget: 11000, used: 5000, remaining: 6000 },
{ id: 6, name: '企画部門B', departmentId: 3, budget: 11000, used: 1000, remaining: 10000 },
{ id: 7, name: '財務部門A', departmentId: 4, budget: 12500, used: 3000, remaining: 9500 },
{ id: 8, name: '財務部門B', departmentId: 4, budget: 12500, used: 2500, remaining: 10000 },
{ id: 9, name: '情報部門A', departmentId: 5, budget: 10500, used: 4000, remaining: 6500 },
{ id: 10, name: '情報部門B', departmentId: 5, budget: 10500, used: 3000, remaining: 7500 },
{ id: 11, name: '総務部門A', departmentId: 6, budget: 11500, used: 2000, remaining: 9500 },
{ id: 12, name: '総務部門B', departmentId: 6, budget: 11500, used: 2500, remaining: 9000 },
];

const items: Item[] = [
{ 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: 5000, used: 2000, remaining: 3000 },
{ id: 4, name: '物品D', divisionId: 2, budget: 5000, used: 0, remaining: 5000 },
{ id: 5, name: '物品E', divisionId: 3, budget: 5000, used: 3000, remaining: 2000 },
{ id: 6, name: '物品F', divisionId: 3, budget: 5000, used: 500, remaining: 4500 },
{ id: 7, name: '物品G', divisionId: 4, budget: 5000, used: 2000, remaining: 3000 },
{ id: 8, name: '物品H', divisionId: 4, budget: 5000, used: 1500, remaining: 3500 },
{ id: 9, name: '物品I', divisionId: 5, budget: 5000, used: 4000, remaining: 1000 },
{ id: 10, name: '物品J', divisionId: 5, budget: 5000, used: 3000, remaining: 2000 },
{ id: 11, name: '物品K', divisionId: 6, budget: 5000, used: 1000, remaining: 4000 },
{ id: 12, name: '物品L', divisionId: 6, budget: 5000, used: 1500, remaining: 3500 },
{ id: 13, name: '物品M', divisionId: 7, budget: 5000, used: 3000, remaining: 2000 },
{ id: 14, name: '物品N', divisionId: 7, budget: 5000, used: 2000, remaining: 3000 },
{ id: 15, name: '物品O', divisionId: 8, budget: 5000, used: 1000, remaining: 4000 },
{ id: 16, name: '物品P', divisionId: 8, budget: 5000, used: 2500, remaining: 2500 },
{ id: 17, name: '物品Q', divisionId: 9, budget: 5000, used: 4000, remaining: 1000 },
{ id: 18, name: '物品R', divisionId: 9, budget: 5000, used: 3000, remaining: 2000 },
{ id: 19, name: '物品S', divisionId: 10, budget: 5000, used: 1000, remaining: 4000 },
{ id: 20, name: '物品T', divisionId: 10, budget: 5000, used: 2500, remaining: 2500 },
{ id: 21, name: '物品U', divisionId: 11, budget: 5000, used: 4000, remaining: 1000 },
{ id: 22, name: '物品V', divisionId: 11, budget: 5000, used: 3000, remaining: 2000 },
{ id: 23, name: '物品W', divisionId: 12, budget: 5000, used: 1000, remaining: 4000 },
{ id: 24, name: '物品X', divisionId: 12, budget: 5000, used: 2500, remaining: 2500 },
];

export const fetchDepartments = async (): Promise<Department[]> => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(departments);
});
});
};

export const fetchDivisions = async (departmentId: number): Promise<Division[]> => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(divisions.filter((division) => division.departmentId === departmentId));
});
});
};

export const fetchItems = async (divisionId: number): Promise<Item[]> => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(items.filter((item) => item.divisionId === divisionId));
});
});
};

0 comments on commit e94e015

Please sign in to comment.