From 3ad7fc2e690b067a3db60f9317949c5e6a2e3426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=97=E3=81=BF?= <37952374+Simirall@users.noreply.github.com> Date: Mon, 19 Aug 2024 21:40:17 +0900 Subject: [PATCH] Feat: Madamis crud (#1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update: add madamis pl, gm column * feat: add madamis ui * madamis create * feat: edit madamis * delete madamis * fix: ただしいgrouping routes * feat: add loading --- migrations/0001_classy_shard.sql | 2 + migrations/meta/0001_snapshot.json | 192 ++++++++++++ migrations/meta/_journal.json | 7 + package.json | 11 +- pnpm-lock.yaml | 420 ++++++++++++++++++++++++++ schema.ts | 2 + src/api.ts | 11 +- src/apis/madamis.ts | 52 ++++ src/apis/user.ts | 12 + src/client.tsx | 19 +- src/component.tsx | 15 - src/index.tsx | 15 +- src/pages/App.tsx | 18 ++ src/pages/components/AddMadamis.tsx | 23 ++ src/pages/components/Header.tsx | 34 +++ src/pages/components/MadamisList.tsx | 63 ++++ src/pages/components/MadamisModal.tsx | 181 +++++++++++ src/pages/hooks/useMadamisList.tsx | 15 + src/pages/stores/madamisModalStore.ts | 22 ++ 19 files changed, 1083 insertions(+), 31 deletions(-) create mode 100644 migrations/0001_classy_shard.sql create mode 100644 migrations/meta/0001_snapshot.json create mode 100644 src/apis/madamis.ts create mode 100644 src/apis/user.ts delete mode 100644 src/component.tsx create mode 100644 src/pages/App.tsx create mode 100644 src/pages/components/AddMadamis.tsx create mode 100644 src/pages/components/Header.tsx create mode 100644 src/pages/components/MadamisList.tsx create mode 100644 src/pages/components/MadamisModal.tsx create mode 100644 src/pages/hooks/useMadamisList.tsx create mode 100644 src/pages/stores/madamisModalStore.ts diff --git a/migrations/0001_classy_shard.sql b/migrations/0001_classy_shard.sql new file mode 100644 index 0000000..0f0ece8 --- /dev/null +++ b/migrations/0001_classy_shard.sql @@ -0,0 +1,2 @@ +ALTER TABLE `Madamis` ADD `player` integer NOT NULL;--> statement-breakpoint +ALTER TABLE `Madamis` ADD `gmRequired` integer NOT NULL; \ No newline at end of file diff --git a/migrations/meta/0001_snapshot.json b/migrations/meta/0001_snapshot.json new file mode 100644 index 0000000..0192336 --- /dev/null +++ b/migrations/meta/0001_snapshot.json @@ -0,0 +1,192 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "41052890-ad09-43a6-baa9-0048bf340820", + "prevId": "e9e38636-7650-4a2a-979b-236f8e3be152", + "tables": { + "GameUsers": { + "name": "GameUsers", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "gameId": { + "name": "gameId", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "GameUsers_gameId_Games_id_fk": { + "name": "GameUsers_gameId_Games_id_fk", + "tableFrom": "GameUsers", + "tableTo": "Games", + "columnsFrom": [ + "gameId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "GameUsers_userId_Users_id_fk": { + "name": "GameUsers_userId_Users_id_fk", + "tableFrom": "GameUsers", + "tableTo": "Users", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "Games": { + "name": "Games", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "date": { + "name": "date", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "madamisId": { + "name": "madamisId", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "Games_madamisId_Madamis_id_fk": { + "name": "Games_madamisId_Madamis_id_fk", + "tableFrom": "Games", + "tableTo": "Madamis", + "columnsFrom": [ + "madamisId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "Madamis": { + "name": "Madamis", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "link": { + "name": "link", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "player": { + "name": "player", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "gmRequired": { + "name": "gmRequired", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "Users": { + "name": "Users", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/migrations/meta/_journal.json b/migrations/meta/_journal.json index 9135378..5476f5b 100644 --- a/migrations/meta/_journal.json +++ b/migrations/meta/_journal.json @@ -8,6 +8,13 @@ "when": 1723995111132, "tag": "0000_fair_hammerhead", "breakpoints": true + }, + { + "idx": 1, + "version": "6", + "when": 1724043283043, + "tag": "0001_classy_shard", + "breakpoints": true } ] } \ No newline at end of file diff --git a/package.json b/package.json index 0dd995c..17e273f 100644 --- a/package.json +++ b/package.json @@ -12,10 +12,19 @@ }, "dependencies": { "@hono/react-renderer": "^0.2.1", + "@hono/zod-validator": "^0.2.2", + "@hookform/resolvers": "^3.9.0", + "@mantine/core": "^7.12.1", + "@mantine/hooks": "^7.12.1", + "@phosphor-icons/react": "^2.1.7", "drizzle-orm": "^0.33.0", "hono": "^4.5.6", "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1", + "react-hook-form": "^7.52.2", + "swr": "^2.2.5", + "zod": "^3.23.8", + "zustand": "^4.5.5" }, "devDependencies": { "@cloudflare/workers-types": "^4.20240529.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c816c3c..3192bd1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,21 @@ importers: '@hono/react-renderer': specifier: ^0.2.1 version: 0.2.1(hono@4.5.6) + '@hono/zod-validator': + specifier: ^0.2.2 + version: 0.2.2(hono@4.5.6)(zod@3.23.8) + '@hookform/resolvers': + specifier: ^3.9.0 + version: 3.9.0(react-hook-form@7.52.2(react@18.3.1)) + '@mantine/core': + specifier: ^7.12.1 + version: 7.12.1(@mantine/hooks@7.12.1(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mantine/hooks': + specifier: ^7.12.1 + version: 7.12.1(react@18.3.1) + '@phosphor-icons/react': + specifier: ^2.1.7 + version: 2.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1) drizzle-orm: specifier: ^0.33.0 version: 0.33.0(@cloudflare/workers-types@4.20240815.0)(@prisma/client@5.18.0)(@types/react@18.3.3)(react@18.3.1) @@ -23,6 +38,18 @@ importers: react-dom: specifier: ^18.3.1 version: 18.3.1(react@18.3.1) + react-hook-form: + specifier: ^7.52.2 + version: 7.52.2(react@18.3.1) + swr: + specifier: ^2.2.5 + version: 2.2.5(react@18.3.1) + zod: + specifier: ^3.23.8 + version: 3.23.8 + zustand: + specifier: ^4.5.5 + version: 4.5.5(@types/react@18.3.3)(react@18.3.1) devDependencies: '@cloudflare/workers-types': specifier: ^4.20240529.0 @@ -54,6 +81,10 @@ importers: packages: + '@babel/runtime@7.25.0': + resolution: {integrity: sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==} + engines: {node: '>=6.9.0'} + '@cloudflare/kv-asset-handler@0.3.4': resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==} engines: {node: '>=16.13'} @@ -662,6 +693,27 @@ packages: resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} engines: {node: '>=14'} + '@floating-ui/core@1.6.7': + resolution: {integrity: sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g==} + + '@floating-ui/dom@1.6.10': + resolution: {integrity: sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A==} + + '@floating-ui/react-dom@2.1.1': + resolution: {integrity: sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/react@0.26.22': + resolution: {integrity: sha512-LNv4azPt8SpT4WW7Kku5JNVjLk2GcS0bGGjFTAgqOONRFo9r/aaGHHPpdiIuQbB1t8shmWyWqTTUDmZ9fcNshg==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.7': + resolution: {integrity: sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==} + '@hono/node-server@1.12.0': resolution: {integrity: sha512-e6oHjNiErRxsZRZBmc2KucuvY3btlO/XPncIpP2X75bRdTilF9GLjm3NHvKKunpJbbJJj31/FoPTksTf8djAVw==} engines: {node: '>=18.14.1'} @@ -684,6 +736,17 @@ packages: peerDependencies: hono: '*' + '@hono/zod-validator@0.2.2': + resolution: {integrity: sha512-dSDxaPV70Py8wuIU2QNpoVEIOSzSXZ/6/B/h4xA7eOMz7+AarKTSGV8E6QwrdcCbBLkpqfJ4Q2TmBO0eP1tCBQ==} + peerDependencies: + hono: '>=3.9.0' + zod: ^3.19.1 + + '@hookform/resolvers@3.9.0': + resolution: {integrity: sha512-bU0Gr4EepJ/EQsH/IwEzYLsT/PEj5C0ynLQ4m+GSHS+xKH4TfSelhluTgOaoc4kA5s7eCsQbM4wvZLzELmWzUg==} + peerDependencies: + react-hook-form: ^7.0.0 + '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} @@ -694,6 +757,25 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@mantine/core@7.12.1': + resolution: {integrity: sha512-PXKIDaT1fpNB77dPQIcdFGM2NRnfmsJSVx3uuBccngBQWMIWI0wPyiO1Y26DK4LQrbrypeb+TS+Zxpgx6RoiCA==} + peerDependencies: + '@mantine/hooks': 7.12.1 + react: ^18.2.0 + react-dom: ^18.2.0 + + '@mantine/hooks@7.12.1': + resolution: {integrity: sha512-YPA3qiMHJkWID5+YzakBaLvjHtX3Fg3PdPY49iIb/CaWM9+lrJ+77TOVS7bsY7ZTBHXUfzft1/6Woqt3xSuweA==} + peerDependencies: + react: ^18.2.0 + + '@phosphor-icons/react@2.1.7': + resolution: {integrity: sha512-g2e2eVAn1XG2a+LI09QU3IORLhnFNAFkNbo2iwbX6NOKSLOwvEMmTa7CgOzEbgNWR47z8i8kwjdvYZ5fkGx1mQ==} + engines: {node: '>=10'} + peerDependencies: + react: '>= 16.8' + react-dom: '>= 16.8' + '@prisma/client@5.18.0': resolution: {integrity: sha512-BWivkLh+af1kqC89zCJYkHsRcyWsM8/JHpsDMM76DjP3ZdEquJhXa4IeX+HkWPnwJ5FanxEJFZZDTWiDs/Kvyw==} engines: {node: '>=16.13'} @@ -844,6 +926,13 @@ packages: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + consola@3.2.3: resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==} engines: {node: ^14.18.0 || >=16.10.0} @@ -873,6 +962,9 @@ packages: defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + drizzle-kit@0.24.0: resolution: {integrity: sha512-rUl5Rf5HLOVkAwHEVEi8xgulIRWzoys0q77RHGCxv5e9v8AI3JGFg7Ug5K1kn513RwNZbuNJMUKOXo0j8kPRgg==} hasBin: true @@ -1014,6 +1106,10 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + get-source@2.0.12: resolution: {integrity: sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==} @@ -1035,6 +1131,9 @@ packages: resolution: {integrity: sha512-9SuUC/zLQv8YAcnIxJko0KCeLI0Q6menPsDWuJ9jaH+r8ZkVXeLqeLs1QJXCPKKbURAWj9x0SJBSFh803EnAUw==} engines: {node: '>=16.0.0'} + invariant@2.2.4: + resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} @@ -1102,6 +1201,10 @@ packages: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} @@ -1130,11 +1233,65 @@ packages: printable-characters@1.0.42: resolution: {integrity: sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==} + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + react-dom@18.3.1: resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} peerDependencies: react: ^18.3.1 + react-hook-form@7.52.2: + resolution: {integrity: sha512-pqfPEbERnxxiNMPd0bzmt1tuaPcVccywFDpyk2uV5xCIBphHV5T8SVnX9/o3kplPE1zzKt77+YIoq+EMwJp56A==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^16.8.0 || ^17 || ^18 || ^19 + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react-number-format@5.4.0: + resolution: {integrity: sha512-NWdICrqLhI7rAS8yUeLVd6Wr4cN7UjJ9IBTS0f/a9i7UB4x4Ti70kGnksBtZ7o4Z7YRbvCMMR/jQmkoOBa/4fg==} + peerDependencies: + react: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + react-dom: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + + react-remove-scroll-bar@2.3.6: + resolution: {integrity: sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.5.10: + resolution: {integrity: sha512-m3zvBRANPBw3qxVVjEIPEQinkcwlFZ4qyomuWVpNJdv4c6MvHfXV0C3L9Jx5rr3HeBHKNRX+1jreB5QloDIJjA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-style-singleton@2.2.1: + resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-textarea-autosize@8.5.3: + resolution: {integrity: sha512-XT1024o2pqCuZSuBt9FwHlaDeNtVrtCXu0Rnz88t1jUGheCLa3PhjE1GH8Ctm2axEtvdCl5SUHYschyQ0L5QHQ==} + engines: {node: '>=10'} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -1143,6 +1300,9 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} @@ -1202,6 +1362,14 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + swr@2.2.5: + resolution: {integrity: sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg==} + peerDependencies: + react: ^16.11.0 || ^17.0.0 || ^18.0.0 + + tabbable@6.2.0: + resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -1209,6 +1377,10 @@ packages: tslib@2.6.3: resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} + type-fest@4.25.0: + resolution: {integrity: sha512-bRkIGlXsnGBRBQRAY56UXBm//9qH4bmJfFvq83gSz41N282df+fjy8ofcEgc1sM8geNt5cl6mC2g9Fht1cs8Aw==} + engines: {node: '>=16'} + ufo@1.5.4: resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} @@ -1222,6 +1394,54 @@ packages: unenv-nightly@1.10.0-1717606461.a117952: resolution: {integrity: sha512-u3TfBX02WzbHTpaEfWEKwDijDSFAHcgXkayUZ+MVDrjhLFvgAJzFGTSTmwlEhwWi2exyRQey23ah9wELMM6etg==} + use-callback-ref@1.3.2: + resolution: {integrity: sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + use-composed-ref@1.3.0: + resolution: {integrity: sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + + use-isomorphic-layout-effect@1.1.2: + resolution: {integrity: sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + use-latest@1.2.1: + resolution: {integrity: sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.2: + resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.9.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + use-sync-external-store@1.2.2: + resolution: {integrity: sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + vite@5.4.1: resolution: {integrity: sha512-1oE6yuNXssjrZdblI9AfBbHCC41nnyoVoEZxQnID6yvQZAFBzxxkqoFLtHUMkYunL8hwOLEjgTuxpkRxvba3kA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -1289,8 +1509,27 @@ packages: zod@3.23.8: resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} + zustand@4.5.5: + resolution: {integrity: sha512-+0PALYNJNgK6hldkgDq2vLrw5f6g/jCInz52n9RTpropGgeAf/ioFUCdtsjCqu4gNhW9D01rUQBROoRjdzyn2Q==} + engines: {node: '>=12.7.0'} + peerDependencies: + '@types/react': '>=16.8' + immer: '>=9.0.6' + react: '>=16.8' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + snapshots: + '@babel/runtime@7.25.0': + dependencies: + regenerator-runtime: 0.14.1 + '@cloudflare/kv-asset-handler@0.3.4': dependencies: mime: 3.0.0 @@ -1612,6 +1851,31 @@ snapshots: '@fastify/busboy@2.1.1': {} + '@floating-ui/core@1.6.7': + dependencies: + '@floating-ui/utils': 0.2.7 + + '@floating-ui/dom@1.6.10': + dependencies: + '@floating-ui/core': 1.6.7 + '@floating-ui/utils': 0.2.7 + + '@floating-ui/react-dom@2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@floating-ui/dom': 1.6.10 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + + '@floating-ui/react@0.26.22(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@floating-ui/react-dom': 2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@floating-ui/utils': 0.2.7 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + tabbable: 6.2.0 + + '@floating-ui/utils@0.2.7': {} + '@hono/node-server@1.12.0': {} '@hono/react-renderer@0.2.1(hono@4.5.6)': @@ -1633,6 +1897,15 @@ snapshots: - supports-color - utf-8-validate + '@hono/zod-validator@0.2.2(hono@4.5.6)(zod@3.23.8)': + dependencies: + hono: 4.5.6 + zod: 3.23.8 + + '@hookform/resolvers@3.9.0(react-hook-form@7.52.2(react@18.3.1))': + dependencies: + react-hook-form: 7.52.2(react@18.3.1) + '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/sourcemap-codec@1.5.0': {} @@ -1642,6 +1915,29 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 + '@mantine/core@7.12.1(@mantine/hooks@7.12.1(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@floating-ui/react': 0.26.22(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mantine/hooks': 7.12.1(react@18.3.1) + clsx: 2.1.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-number-format: 5.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react-remove-scroll: 2.5.10(@types/react@18.3.3)(react@18.3.1) + react-textarea-autosize: 8.5.3(@types/react@18.3.3)(react@18.3.1) + type-fest: 4.25.0 + transitivePeerDependencies: + - '@types/react' + + '@mantine/hooks@7.12.1(react@18.3.1)': + dependencies: + react: 18.3.1 + + '@phosphor-icons/react@2.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + '@prisma/client@5.18.0': optional: true @@ -1764,6 +2060,10 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + client-only@0.0.1: {} + + clsx@2.1.1: {} + consola@3.2.3: {} cookie@0.5.0: {} @@ -1780,6 +2080,8 @@ snapshots: defu@6.1.4: {} + detect-node-es@1.1.0: {} + drizzle-kit@0.24.0: dependencies: '@drizzle-team/brocli': 0.8.2 @@ -1920,6 +2222,8 @@ snapshots: function-bind@1.1.2: {} + get-nonce@1.0.1: {} + get-source@2.0.12: dependencies: data-uri-to-buffer: 2.0.2 @@ -1941,6 +2245,10 @@ snapshots: hono@4.5.6: {} + invariant@2.2.4: + dependencies: + loose-envify: 1.4.0 + is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 @@ -2004,6 +2312,8 @@ snapshots: normalize-path@3.0.0: {} + object-assign@4.1.1: {} + path-parse@1.0.7: {} path-to-regexp@6.2.2: {} @@ -2024,12 +2334,67 @@ snapshots: printable-characters@1.0.42: {} + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + react-dom@18.3.1(react@18.3.1): dependencies: loose-envify: 1.4.0 react: 18.3.1 scheduler: 0.23.2 + react-hook-form@7.52.2(react@18.3.1): + dependencies: + react: 18.3.1 + + react-is@16.13.1: {} + + react-number-format@5.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + prop-types: 15.8.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + + react-remove-scroll-bar@2.3.6(@types/react@18.3.3)(react@18.3.1): + dependencies: + react: 18.3.1 + react-style-singleton: 2.2.1(@types/react@18.3.3)(react@18.3.1) + tslib: 2.6.3 + optionalDependencies: + '@types/react': 18.3.3 + + react-remove-scroll@2.5.10(@types/react@18.3.3)(react@18.3.1): + dependencies: + react: 18.3.1 + react-remove-scroll-bar: 2.3.6(@types/react@18.3.3)(react@18.3.1) + react-style-singleton: 2.2.1(@types/react@18.3.3)(react@18.3.1) + tslib: 2.6.3 + use-callback-ref: 1.3.2(@types/react@18.3.3)(react@18.3.1) + use-sidecar: 1.1.2(@types/react@18.3.3)(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.3 + + react-style-singleton@2.2.1(@types/react@18.3.3)(react@18.3.1): + dependencies: + get-nonce: 1.0.1 + invariant: 2.2.4 + react: 18.3.1 + tslib: 2.6.3 + optionalDependencies: + '@types/react': 18.3.3 + + react-textarea-autosize@8.5.3(@types/react@18.3.3)(react@18.3.1): + dependencies: + '@babel/runtime': 7.25.0 + react: 18.3.1 + use-composed-ref: 1.3.0(react@18.3.1) + use-latest: 1.2.1(@types/react@18.3.3)(react@18.3.1) + transitivePeerDependencies: + - '@types/react' + react@18.3.1: dependencies: loose-envify: 1.4.0 @@ -2038,6 +2403,8 @@ snapshots: dependencies: picomatch: 2.3.1 + regenerator-runtime@0.14.1: {} + resolve-pkg-maps@1.0.0: {} resolve.exports@2.0.2: {} @@ -2113,12 +2480,22 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} + swr@2.2.5(react@18.3.1): + dependencies: + client-only: 0.0.1 + react: 18.3.1 + use-sync-external-store: 1.2.2(react@18.3.1) + + tabbable@6.2.0: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 tslib@2.6.3: {} + type-fest@4.25.0: {} + ufo@1.5.4: {} undici-types@6.19.6: {} @@ -2136,6 +2513,42 @@ snapshots: pathe: 1.1.2 ufo: 1.5.4 + use-callback-ref@1.3.2(@types/react@18.3.3)(react@18.3.1): + dependencies: + react: 18.3.1 + tslib: 2.6.3 + optionalDependencies: + '@types/react': 18.3.3 + + use-composed-ref@1.3.0(react@18.3.1): + dependencies: + react: 18.3.1 + + use-isomorphic-layout-effect@1.1.2(@types/react@18.3.3)(react@18.3.1): + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.3 + + use-latest@1.2.1(@types/react@18.3.3)(react@18.3.1): + dependencies: + react: 18.3.1 + use-isomorphic-layout-effect: 1.1.2(@types/react@18.3.3)(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.3 + + use-sidecar@1.1.2(@types/react@18.3.3)(react@18.3.1): + dependencies: + detect-node-es: 1.1.0 + react: 18.3.1 + tslib: 2.6.3 + optionalDependencies: + '@types/react': 18.3.3 + + use-sync-external-store@1.2.2(react@18.3.1): + dependencies: + react: 18.3.1 + vite@5.4.1(@types/node@22.4.0): dependencies: esbuild: 0.21.5 @@ -2192,3 +2605,10 @@ snapshots: stacktracey: 2.1.8 zod@3.23.8: {} + + zustand@4.5.5(@types/react@18.3.3)(react@18.3.1): + dependencies: + use-sync-external-store: 1.2.2(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.3 + react: 18.3.1 diff --git a/schema.ts b/schema.ts index e521a85..867fd0e 100644 --- a/schema.ts +++ b/schema.ts @@ -5,6 +5,8 @@ export const madamis = sqliteTable("Madamis", { id: integer("id", { mode: "number" }).primaryKey({ autoIncrement: true }), title: text("title").notNull(), link: text("link").notNull(), + player: integer("player").notNull(), + gmRequired: integer("gmRequired").notNull(), }); export const madamisRelations = relations(madamis, ({ many }) => ({ diff --git a/src/api.ts b/src/api.ts index 017d147..6d3c1fe 100644 --- a/src/api.ts +++ b/src/api.ts @@ -1,12 +1,9 @@ -import { drizzle } from "drizzle-orm/d1"; import { Hono } from "hono"; -import { users } from "../schema"; +import { userApp } from "./apis/user"; +import { madamisApp } from "./apis/madamis"; export const api = new Hono<{ Bindings: Env }>(); -api.get("users/", async (c) => { - const db = drizzle(c.env.DB); +const app = api.route("/user", userApp).route("/madamis", madamisApp); - const result = await db.select().from(users).all(); - return c.json(result); -}); +export type AppType = typeof app; diff --git a/src/apis/madamis.ts b/src/apis/madamis.ts new file mode 100644 index 0000000..e219cec --- /dev/null +++ b/src/apis/madamis.ts @@ -0,0 +1,52 @@ +import { drizzle } from "drizzle-orm/d1"; +import { Hono } from "hono"; +import { madamis } from "../../schema"; +import { z } from "zod"; +import { zValidator } from "@hono/zod-validator"; +import { eq } from "drizzle-orm"; + +const madamisPostSchema = z.object({ + title: z.string().min(1), + link: z.string().url(), + player: z.number().int().min(1).max(6), + gmRequired: z.boolean().transform((b) => Number(b)), +}); + +const madamisPutSchema = madamisPostSchema.extend({ + id: z.number().int(), +}); + +const madamisApi = new Hono<{ Bindings: Env }>(); + +export const madamisApp = madamisApi + .get("/", async (c) => { + const db = drizzle(c.env.DB); + + const result = await db.select().from(madamis); + return c.json(result); + }) + .post("/", zValidator("json", madamisPostSchema), async (c) => { + const db = drizzle(c.env.DB); + const body = c.req.valid("json"); + + const [result] = await db.insert(madamis).values(body).returning(); + return c.json(result); + }) + .put("/", zValidator("json", madamisPutSchema), async (c) => { + const db = drizzle(c.env.DB); + const body = c.req.valid("json"); + + const [result] = await db + .update(madamis) + .set(body) + .where(eq(madamis.id, body.id)) + .returning(); + return c.json(result); + }) + .delete("/:id", async (c) => { + const db = drizzle(c.env.DB); + const id = c.req.param("id"); + + await db.delete(madamis).where(eq(madamis.id, parseInt(id))); + return new Response(null, { status: 204 }); + }); diff --git a/src/apis/user.ts b/src/apis/user.ts new file mode 100644 index 0000000..9cf3469 --- /dev/null +++ b/src/apis/user.ts @@ -0,0 +1,12 @@ +import { drizzle } from "drizzle-orm/d1"; +import { Hono } from "hono"; +import { users } from "../../schema"; + +const userApi = new Hono<{ Bindings: Env }>(); + +export const userApp = userApi.get("/", async (c) => { + const db = drizzle(c.env.DB); + + const result = await db.select().from(users).all(); + return c.json(result); +}); diff --git a/src/client.tsx b/src/client.tsx index 7a2c094..8fee3af 100644 --- a/src/client.tsx +++ b/src/client.tsx @@ -1,13 +1,24 @@ import { createRoot } from "react-dom/client"; -import { Component } from "./component"; -const App = () => { +import "@mantine/core/styles.css"; +import { createTheme, MantineProvider } from "@mantine/core"; +import { App } from "./pages/App"; + +const theme = createTheme({ + fontFamily: `"Yusei Magic", sans-serif`, + headings: { fontFamily: `"Yusei Magic", sans-serif` }, + primaryColor: "lime", +}); + +const Index = () => { return ( <> - Hello, + + + ); }; const root = createRoot(document.getElementById("root")!); -root.render(); +root.render(); diff --git a/src/component.tsx b/src/component.tsx deleted file mode 100644 index 23d18d8..0000000 --- a/src/component.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { useState } from "react"; - -export const Component = () => { - const [c, uc] = useState(0); - - return ( - - ); -}; diff --git a/src/index.tsx b/src/index.tsx index 9919f05..cec06f0 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -4,17 +4,24 @@ import { renderToString } from "react-dom/server"; const app = new Hono(); -app.route("/api/", api); - -app.get("*", (c) => { +app.route("/api", api).get("*", (c) => { return c.html( renderToString( + j∞マダミス部 + + + {import.meta.env.PROD ? ( - + <> + + ) : ( )} diff --git a/src/pages/App.tsx b/src/pages/App.tsx new file mode 100644 index 0000000..0eb6154 --- /dev/null +++ b/src/pages/App.tsx @@ -0,0 +1,18 @@ +import { Container } from "@mantine/core"; +import { Header } from "./components/Header"; +import { AddMadamisButton } from "./components/AddMadamis"; +import { MadamisList } from "./components/MadamisList"; +import { MadamisModal } from "./components/MadamisModal"; + +export const App = () => { + return ( + <> +
+ + + + + + + ); +}; diff --git a/src/pages/components/AddMadamis.tsx b/src/pages/components/AddMadamis.tsx new file mode 100644 index 0000000..7f8ddc8 --- /dev/null +++ b/src/pages/components/AddMadamis.tsx @@ -0,0 +1,23 @@ +import { ActionIcon, Box } from "@mantine/core"; +import { Plus } from "@phosphor-icons/react"; +import { useMadamisModalStore } from "../stores/madamisModalStore"; + +export const AddMadamisButton = () => { + const { createOpen } = useMadamisModalStore(); + return ( + <> + + + + + + + ); +}; diff --git a/src/pages/components/Header.tsx b/src/pages/components/Header.tsx new file mode 100644 index 0000000..600ac44 --- /dev/null +++ b/src/pages/components/Header.tsx @@ -0,0 +1,34 @@ +import { ActionIcon, Group, Title, useMantineColorScheme } from "@mantine/core"; +import { MoonStars, Sun } from "@phosphor-icons/react"; + +export const Header = () => { + return ( + + + J∞マダミス部 + + + + ); +}; + +const ColorModeToggle = () => { + const { colorScheme, toggleColorScheme } = useMantineColorScheme(); + return ( + { + toggleColorScheme(); + }} + > + {colorScheme === "light" ? ( + + ) : ( + + )} + + ); +}; diff --git a/src/pages/components/MadamisList.tsx b/src/pages/components/MadamisList.tsx new file mode 100644 index 0000000..9fcc565 --- /dev/null +++ b/src/pages/components/MadamisList.tsx @@ -0,0 +1,63 @@ +import { ActionIcon, Badge, Card, Group, NavLink, Stack } from "@mantine/core"; +import { Link, PencilSimple } from "@phosphor-icons/react"; +import { useMadamisList } from "../hooks/useMadamisList"; +import { useMadamisModalStore } from "../stores/madamisModalStore"; + +export const MadamisList = () => { + const { data } = useMadamisList(); + const { editOpen } = useMadamisModalStore(); + + return ( + <> + + {data && + data.map((d) => ( + + + + } + style={{ + borderRadius: "4px", + }} + /> + + + + GM: {d.gmRequired ? "要" : "レス可"} + + + PL: {d.player}人 + + + { + editOpen(d.id); + }} + /> + + + + + ))} + + + ); +}; diff --git a/src/pages/components/MadamisModal.tsx b/src/pages/components/MadamisModal.tsx new file mode 100644 index 0000000..18fd220 --- /dev/null +++ b/src/pages/components/MadamisModal.tsx @@ -0,0 +1,181 @@ +import { + Button, + Checkbox, + Fieldset, + Group, + Modal, + NativeSelect, + Stack, + TextInput, +} from "@mantine/core"; +import { useDisclosure } from "@mantine/hooks"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { hc } from "hono/client"; +import { useMadamisList } from "../hooks/useMadamisList"; +import { useMadamisModalStore } from "../stores/madamisModalStore"; +import { useEffect, useState } from "react"; +import { AppType } from "../../api"; + +const formSchema = z.object({ + title: z.string().min(1), + link: z.string().url(), + player: z.coerce.number().int().min(1).max(6), + gmRequired: z.boolean(), +}); + +type FormSchema = z.infer; + +const client = hc("/api"); + +export const MadamisModal = () => { + const { data, mutate } = useMadamisList(); + + const { open, close, madamisId } = useMadamisModalStore(); + const [loading, setLoading] = useState(false); + + const editData = madamisId + ? data?.find((d) => d.id === madamisId) + : undefined; + + const { + register, + reset, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(formSchema), + }); + + const onSubmit = async (data: FormSchema) => { + setLoading(true); + if (madamisId) { + await client.madamis.$put({ + json: { id: madamisId, ...data }, + }); + } else { + await client.madamis.$post({ + json: data, + }); + } + await mutate(); + close(); + setLoading(false); + }; + + useEffect(() => { + reset(); + }, [madamisId, open]); + + return ( + { + reset(); + close(); + }} + title={`マダミスを${editData ? "編集" : "追加"}`} + centered + closeOnClickOutside={false} + > +
+
+ + + + + + + {madamisId && ( + + )} + +
+
+
+ ); +}; + +const DeleteMadamis = ({ + madamisId, + parentLoading, +}: { + madamisId: number; + parentLoading: boolean; +}) => { + const { close: closeMadamisModal } = useMadamisModalStore(); + const { mutate } = useMadamisList(); + + const [opened, { open, close }] = useDisclosure(false); + const [loading, setLoading] = useState(false); + + const onDelete = async () => { + setLoading(true); + await client.madamis[":id"].$delete({ + param: { id: madamisId.toString() }, + }); + await mutate(); + close(); + closeMadamisModal(); + }; + + return ( + <> + + + + + + + + + ); +}; diff --git a/src/pages/hooks/useMadamisList.tsx b/src/pages/hooks/useMadamisList.tsx new file mode 100644 index 0000000..52ed072 --- /dev/null +++ b/src/pages/hooks/useMadamisList.tsx @@ -0,0 +1,15 @@ +import useSWR from "swr"; +import { hc } from "hono/client"; +import { AppType } from "../../api"; + +const client = hc; + +export const useMadamisList = () => { + const { data, mutate } = useSWR("/api/madamis", (path) => + client("/api") + .madamis.$get() + .then((res) => res.json()) + ); + + return { data, mutate }; +}; diff --git a/src/pages/stores/madamisModalStore.ts b/src/pages/stores/madamisModalStore.ts new file mode 100644 index 0000000..5dd28de --- /dev/null +++ b/src/pages/stores/madamisModalStore.ts @@ -0,0 +1,22 @@ +import { create } from "zustand"; + +type MadamisModalState = { + open: boolean; + madamisId?: number; +}; + +type MadamisModalAction = { + createOpen: () => void; + editOpen: (id: number) => void; + close: () => void; +}; + +export const useMadamisModalStore = create< + MadamisModalState & MadamisModalAction +>((set) => ({ + open: false, + madamisId: undefined, + createOpen: () => set(() => ({ open: true })), + editOpen: (id) => set(() => ({ open: true, madamisId: id })), + close: () => set(() => ({ open: false, madamisId: undefined })), +}));