[ Home ]
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://bolt.new/


作成したコード

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


...
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>
  );
}