Skip to content

Commit e97fcde

Browse files
committed
お知らせ配信の見た目を作成
1 parent 71a2245 commit e97fcde

File tree

1 file changed

+159
-3
lines changed

1 file changed

+159
-3
lines changed
Lines changed: 159 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,161 @@
1-
import React from "react";
1+
"use client";
2+
import { useEffect, useState } from "react";
23

3-
export default function notification() {
4-
return <div>お知らせ配信</div>;
4+
// モックデータ
5+
const mockNotifications = [
6+
{
7+
id: 1,
8+
title: "システムメンテナンス",
9+
content: "12月20日にシステムメンテナンスを行います。",
10+
},
11+
{
12+
id: 2,
13+
title: "新機能リリース",
14+
content: "新しい機能がリリースされました。",
15+
},
16+
];
17+
18+
// 型定義
19+
type Notification = {
20+
id: number;
21+
title: string;
22+
content: string;
23+
};
24+
25+
export default function NotificationAdmin() {
26+
// useStateに型を明示的に指定
27+
const [notifications, setNotifications] = useState<Notification[]>([]);
28+
const [form, setForm] = useState<Notification>({
29+
id: 0,
30+
title: "",
31+
content: "",
32+
});
33+
const [isEditing, setIsEditing] = useState(false);
34+
35+
useEffect(() => {
36+
// 初期データを設定
37+
setNotifications(mockNotifications);
38+
}, []);
39+
40+
// 入力フォームの変更処理
41+
const handleInputChange = (
42+
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
43+
) => {
44+
const { name, value } = e.target;
45+
setForm({ ...form, [name]: value });
46+
};
47+
48+
// 新しいお知らせを追加
49+
const handleAdd = () => {
50+
if (!form.title || !form.content)
51+
return alert("タイトルと内容を入力してください");
52+
const newNotification: Notification = { ...form, id: Date.now() };
53+
setNotifications([...notifications, newNotification]);
54+
setForm({ id: 0, title: "", content: "" });
55+
};
56+
57+
// お知らせを編集
58+
const handleEdit = (notification: Notification) => {
59+
setIsEditing(true);
60+
setForm(notification);
61+
};
62+
63+
// 編集内容を保存
64+
const handleUpdate = () => {
65+
if (!form.title || !form.content)
66+
return alert("タイトルと内容を入力してください");
67+
setNotifications(
68+
notifications.map((n) => (n.id === form.id ? { ...form } : n)),
69+
);
70+
setForm({ id: 0, title: "", content: "" });
71+
setIsEditing(false);
72+
};
73+
74+
// お知らせを削除
75+
const handleDelete = (id: number) => {
76+
if (window.confirm("本当に削除しますか?")) {
77+
setNotifications(notifications.filter((n) => n.id !== id));
78+
}
79+
};
80+
81+
return (
82+
<div className="p-6">
83+
<h1 className="mb-4 font-bold text-2xl">お知らせ配信</h1>
84+
85+
{/* 一覧表示 */}
86+
<div className="mb-6">
87+
<h2 className="mb-2 font-semibold text-xl">お知らせ一覧</h2>
88+
<table className="w-full table-auto border-collapse">
89+
<thead>
90+
<tr className="border-b">
91+
<th className="px-4 py-2 text-left">タイトル</th>
92+
<th className="px-4 py-2 text-left">内容</th>
93+
<th className="px-4 py-2">操作</th>
94+
</tr>
95+
</thead>
96+
<tbody>
97+
{notifications.map((notification) => (
98+
<tr key={notification.id} className="border-b">
99+
<td className="px-4 py-2">{notification.title}</td>
100+
<td className="px-4 py-2">{notification.content}</td>
101+
<td className="px-4 py-2 text-center">
102+
{/* biome-ignore lint/a11y/useButtonType: <explanation> */}
103+
<button
104+
className="mr-2 text-blue-600"
105+
onClick={() => handleEdit(notification)}
106+
>
107+
編集
108+
</button>
109+
{/* biome-ignore lint/a11y/useButtonType: <explanation> */}
110+
<button
111+
className="text-red-600"
112+
onClick={() => handleDelete(notification.id)}
113+
>
114+
削除
115+
</button>
116+
</td>
117+
</tr>
118+
))}
119+
</tbody>
120+
</table>
121+
</div>
122+
123+
{/* フォーム */}
124+
<div>
125+
<h2 className="mb-2 font-semibold text-xl">
126+
{isEditing ? "お知らせを編集" : "新しいお知らせを作成"}
127+
</h2>
128+
<div className="mb-4">
129+
{/* biome-ignore lint/nursery/useSortedClasses: <explanation> */}
130+
{/* biome-ignore lint/a11y/noLabelWithoutControl: <explanation> */}
131+
<label className="block mb-2">タイトル</label>
132+
<input
133+
className="w-full rounded border px-4 py-2"
134+
type="text"
135+
name="title"
136+
value={form.title}
137+
onChange={handleInputChange}
138+
/>
139+
</div>
140+
<div className="mb-4">
141+
{/* biome-ignore lint/a11y/noLabelWithoutControl: <explanation> */}
142+
<label className="mb-2 block">内容</label>
143+
{/* biome-ignore lint/style/useSelfClosingElements: <explanation> */}
144+
<textarea
145+
className="w-full rounded border px-4 py-2"
146+
name="content"
147+
value={form.content}
148+
onChange={handleInputChange}
149+
></textarea>
150+
</div>
151+
{/* biome-ignore lint/a11y/useButtonType: <explanation> */}
152+
<button
153+
className="rounded bg-blue-500 px-4 py-2 text-white"
154+
onClick={isEditing ? handleUpdate : handleAdd}
155+
>
156+
{isEditing ? "更新" : "追加"}
157+
</button>
158+
</div>
159+
</div>
160+
);
5161
}

0 commit comments

Comments
 (0)