back
bolt.new 生成、日程表アプリ 修正例 shadcnUI + React
id: 173, 2024-10-13
概要:
生成AI的な、bolt.new使用して。アプリ作成後、機能追加等のメモになります。
- 日程データ(配列データ)の、サーバー保存の追加になります。
[ 公開日: 2024/10/12 ]
構成
- bolt.new
- shadcn/ui
- Express.js
- esbuild
- typescript
関連
作成したコード
https://github.com/kuc-arc-f/bolt_4example/tree/main/plan2
レイアウト参考
https://sizu.me/knaka0209/posts/twbii18dr682
dev-start
bun run build
bun run dev
- TOP画面
- plan2/src/App.tsx
- https://github.com/kuc-arc-f/bolt_4example/blob/main/plan2/src/App.tsx
...
function App() {
const [date, setDate] = useState<Date | undefined>(new Date());
const [content, setContent] = useState("");
const [scheduleEntries, setScheduleEntries] = useState<ScheduleEntry[]>([]);
const [editingEntry, setEditingEntry] = useState<ScheduleEntry | null>(null);
//
useEffect(() => {
(async() => {
const d = await CrudIndex.getList();
setScheduleEntries(d);
console.log(d);
})()
}, []);
const handleAddEntry = async() => {
if (date && content) {
console.log("date=", format(date, "yyyy-MM-dd"));
//console.log("toISOString=", date.toISOString());
const newEntry = {
id: Date.now().toString(),
date: date.toISOString(),
content
};
let resulte = await CrudIndex.create(newEntry);
console.log(resulte);
setScheduleEntries(resulte);
setContent("");
}
};
const handleEditEntry = (entry: ScheduleEntry) => {
setEditingEntry(entry);
setDate(entry.date);
setContent(entry.content);
};
const handleUpdateEntry = async() => {
if (editingEntry && date && content) {
const updatedEntries = scheduleEntries.map(entry =>
entry.id === editingEntry.id ? { ...entry, date, content } : entry
);
//console.log(updatedEntries);
const target = {
id: editingEntry.id,
date: date.toISOString(),
content
};
let resulte = await CrudIndex.update(target);
console.log(resulte);
setScheduleEntries(resulte);
setEditingEntry(null);
setContent("");
}
};
//
const handleCancelEdit = () => {
setEditingEntry(null);
setContent("");
};
//
const handleDeleteEntry = async (id: string) => {
const resulte = await CrudIndex.delete(id);
const d = await CrudIndex.getList();
//console.log(d);
setScheduleEntries(d);
};
return (
<div className="container mx-auto p-4">
<h1 className="text-3xl font-bold mb-6">月単位スケジュール</h1>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<Card>
<CardHeader>
<CardTitle>カレンダー</CardTitle>
</CardHeader>
<CardContent>
<Calendar
mode="single"
selected={date}
onSelect={setDate}
className="rounded-md border"
locale={ja}
/>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>{editingEntry ? "スケジュール編集" : "スケジュール入力"}</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div>
<label htmlFor="date" className="block text-sm font-medium text-gray-700">
日付
</label>
<Input
type="date"
id="date"
value={date ? format(date, "yyyy-MM-dd") : ""}
onChange={(e) => setDate(new Date(e.target.value))}
className="mt-1"
/>
</div>
<div>
<label htmlFor="content" className="block text-sm font-medium text-gray-700">
内容
</label>
<Textarea
id="content"
value={content}
onChange={(e) => setContent(e.target.value)}
className="mt-1"
rows={4}
/>
</div>
{editingEntry ? (
<div className="flex space-x-2">
<Button onClick={handleUpdateEntry}>更新</Button>
<Button variant="outline" onClick={handleCancelEdit}>キャンセル</Button>
</div>
) : (
<Button onClick={handleAddEntry}>追加</Button>
)}
</div>
</CardContent>
</Card>
</div>
<Card className="mt-6">
<CardHeader>
<CardTitle>スケジュール一覧</CardTitle>
</CardHeader>
<CardContent>
<ul className="space-y-2">
{scheduleEntries.map((entry) => (
<li key={entry.id} className="border-b pb-2 flex justify-between items-center">
<span>
<strong>{format(entry.date, "yyyy年MM月dd日", { locale: ja })}</strong>: {entry.content}
</span>
<div className="flex space-x-2">
<Button variant="outline" size="sm" onClick={() => handleEditEntry(entry)}>
編集
</Button>
<Button variant="destructive" size="sm" onClick={() => {
if (window.confirm("Delete OK?")) {
handleDeleteEntry(entry.id);
}
}}>
<Trash2 className="h-4 w-4" />
</Button>
</div>
</li>
))}
</ul>
</CardContent>
</Card>
</div>
);
}