From d0720190519758a4629f0b55b3f9f143f17f42be Mon Sep 17 00:00:00 2001 From: yukionishi1129 Date: Sat, 4 Jan 2025 00:25:40 +0900 Subject: [PATCH 01/19] fix --- web/client-v2/src/lib/date.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/client-v2/src/lib/date.ts b/web/client-v2/src/lib/date.ts index ae728b94..70dd9329 100644 --- a/web/client-v2/src/lib/date.ts +++ b/web/client-v2/src/lib/date.ts @@ -40,7 +40,7 @@ export const diffDates = (nowUnixTime: number, targetUnixTime: number) => { export const showDiffDateToCurrentDate = (targetDateUnix: number) => { const currentUnixTime = convertUnixTime(getDayjsTz()); - const targetUnixTimeDay = convertUnixTimeToDayjs(currentUnixTime); + const targetUnixTimeDay = convertUnixTimeToDayjs(targetDateUnix); const diffHour = diffHours(currentUnixTime, targetDateUnix); if (diffHour < 24) { From 9cbce31b0a4e727a169be6e9fba6fcfaefeff75f Mon Sep 17 00:00:00 2001 From: YukiOnishi <58220747+YukiOnishi1129@users.noreply.github.com> Date: Sat, 4 Jan 2025 15:50:59 +0900 Subject: [PATCH 02/19] fix zoom size --- web/client-v2/package-lock.json | 365 ++++++++++++++++-- web/client-v2/package.json | 2 +- .../src/components/ui/image/ZoomableImage.tsx | 2 +- web/client-v2/src/components/ui/select.tsx | 160 ++++++++ web/client-v2/src/constant/navigation.ts | 13 + .../SelectArticlePageTab.tsx | 92 +++++ .../Tab/SelectArticlePageTab/index.ts | 1 + .../features/articles/components/Tab/index.ts | 1 + .../ArticleDashboardTemplate.tsx | 3 +- .../TrendArticleDashboardTemplate.tsx | 4 +- 10 files changed, 605 insertions(+), 38 deletions(-) create mode 100644 web/client-v2/src/components/ui/select.tsx create mode 100644 web/client-v2/src/constant/navigation.ts create mode 100644 web/client-v2/src/features/articles/components/Tab/SelectArticlePageTab/SelectArticlePageTab.tsx create mode 100644 web/client-v2/src/features/articles/components/Tab/SelectArticlePageTab/index.ts create mode 100644 web/client-v2/src/features/articles/components/Tab/index.ts diff --git a/web/client-v2/package-lock.json b/web/client-v2/package-lock.json index 64d457f2..c2ec11b6 100644 --- a/web/client-v2/package-lock.json +++ b/web/client-v2/package-lock.json @@ -22,7 +22,7 @@ "@radix-ui/react-navigation-menu": "^1.1.4", "@radix-ui/react-popover": "^1.0.7", "@radix-ui/react-radio-group": "^1.2.2", - "@radix-ui/react-select": "^2.1.1", + "@radix-ui/react-select": "^2.1.4", "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-switch": "^1.0.3", "@radix-ui/react-tabs": "^1.1.0", @@ -5162,32 +5162,304 @@ } }, "node_modules/@radix-ui/react-select": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.1.tgz", - "integrity": "sha512-8iRDfyLtzxlprOo9IicnzvpsO1wNCkuwzzCM+Z5Rb5tNOpCdMvcc2AkzX0Fz+Tz9v6NJ5B/7EEgyZveo4FBRfQ==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.4.tgz", + "integrity": "sha512-pOkb2u8KgO47j/h7AylCj7dJsm69BXcjkrvTqMptFqsE2i0p8lHkfgneXKjAgPzBMivnoMyt8o4KiV4wYzDdyQ==", "license": "MIT", "dependencies": { "@radix-ui/number": "1.1.0", - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-collection": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-collection": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", - "@radix-ui/react-dismissable-layer": "1.1.0", - "@radix-ui/react-focus-guards": "1.1.0", - "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.3", + "@radix-ui/react-focus-guards": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.1", "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-popper": "1.2.0", - "@radix-ui/react-portal": "1.1.1", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-popper": "1.2.1", + "@radix-ui/react-portal": "1.1.3", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-slot": "1.1.1", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-controllable-state": "1.1.0", "@radix-ui/react-use-layout-effect": "1.1.0", "@radix-ui/react-use-previous": "1.1.0", - "@radix-ui/react-visually-hidden": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.1", "aria-hidden": "^1.1.1", - "react-remove-scroll": "2.5.7" + "react-remove-scroll": "^2.6.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", + "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-arrow": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.1.tgz", + "integrity": "sha512-NaVpZfmv8SKeZbn4ijN2V3jlHA9ngBG16VnIIm22nUR0Yk8KUALyBxT3KYEUnNuch9sTE8UTsS3whzBgKOL30w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-collection": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.1.tgz", + "integrity": "sha512-LwT3pSho9Dljg+wY2KN2mrrh6y3qELfftINERIzBUO9e0N+t0oMTyn3k9iv+ZqgrwGkRnLpNJrsMv9BZlt2yuA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-slot": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", + "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-context": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz", + "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.3.tgz", + "integrity": "sha512-onrWn/72lQoEucDmJnr8uczSNTujT0vJnA/X5+3AkChVPowr8n1yvIKIabhWyMQeMvvmdpsvcyDqx3X1LEXCPg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-escape-keydown": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz", + "integrity": "sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.1.tgz", + "integrity": "sha512-01omzJAYRxXdG2/he/+xy+c8a8gCydoQ1yOxnWNcRhrrBW5W+RQJ22EK1SaO8tb3WoUsuEw7mJjBozPzihDFjA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-popper": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.1.tgz", + "integrity": "sha512-3kn5Me69L+jv82EKRuQCXdYyf1DqHwD2U/sxoNgBGCB7K9TRc3bQamQ+5EPM9EvyPdli0W41sROd+ZU1dTCztw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-rect": "1.1.0", + "@radix-ui/react-use-size": "1.1.0", + "@radix-ui/rect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-portal": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.3.tgz", + "integrity": "sha512-NciRqhXnGojhT93RPyDaMPfLH3ZSl4jjIFbZQ1b/vxvZEdHsBZ49wP9w8L3HzUQwep01LcWtkUvm0OVB5JAHTw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-primitive": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz", + "integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-slot": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz", + "integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-visually-hidden": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.1.tgz", + "integrity": "sha512-vVfA2IZ9q/J+gEamvj761Oq1FpWgCDaNOOIfbPVp2MVPLEomUr5+Vf7kJGwQ24YxZSlQVar7Bes8kyTo5Dshpg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.1" }, "peerDependencies": { "@types/react": "*", @@ -5204,6 +5476,31 @@ } } }, + "node_modules/@radix-ui/react-select/node_modules/react-remove-scroll": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.2.tgz", + "integrity": "sha512-KmONPx5fnlXYJQqC62Q+lwIeAk64ws/cUw6omIumRzMRPqgnYqhSSti99nbj0Ry13bv7dF+BKn7NB+OqkdZGTw==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.1", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", @@ -11160,6 +11457,7 @@ "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, "license": "MIT", "dependencies": { "loose-envify": "^1.0.0" @@ -13952,20 +14250,20 @@ } }, "node_modules/react-remove-scroll-bar": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz", - "integrity": "sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", "license": "MIT", "dependencies": { - "react-style-singleton": "^2.2.1", + "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "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" + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -13997,21 +14295,20 @@ } }, "node_modules/react-style-singleton": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", - "integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", "license": "MIT", "dependencies": { "get-nonce": "^1.0.0", - "invariant": "^2.2.4", "tslib": "^2.0.0" }, "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" + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { @@ -15750,9 +16047,9 @@ "license": "MIT" }, "node_modules/use-callback-ref": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.2.tgz", - "integrity": "sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", "license": "MIT", "dependencies": { "tslib": "^2.0.0" @@ -15761,8 +16058,8 @@ "node": ">=10" }, "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { diff --git a/web/client-v2/package.json b/web/client-v2/package.json index 2db78294..b550013b 100644 --- a/web/client-v2/package.json +++ b/web/client-v2/package.json @@ -28,7 +28,7 @@ "@radix-ui/react-navigation-menu": "^1.1.4", "@radix-ui/react-popover": "^1.0.7", "@radix-ui/react-radio-group": "^1.2.2", - "@radix-ui/react-select": "^2.1.1", + "@radix-ui/react-select": "^2.1.4", "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-switch": "^1.0.3", "@radix-ui/react-tabs": "^1.1.0", diff --git a/web/client-v2/src/components/ui/image/ZoomableImage.tsx b/web/client-v2/src/components/ui/image/ZoomableImage.tsx index 3ea8a215..153f3a25 100644 --- a/web/client-v2/src/components/ui/image/ZoomableImage.tsx +++ b/web/client-v2/src/components/ui/image/ZoomableImage.tsx @@ -15,7 +15,7 @@ export const ZoomableImage: FC = ({ imageUrl, alt }) => {
{/* eslint-disable-next-line @next/next/no-img-element */} {alt} diff --git a/web/client-v2/src/components/ui/select.tsx b/web/client-v2/src/components/ui/select.tsx new file mode 100644 index 00000000..cbe5a36b --- /dev/null +++ b/web/client-v2/src/components/ui/select.tsx @@ -0,0 +1,160 @@ +"use client" + +import * as React from "react" +import * as SelectPrimitive from "@radix-ui/react-select" +import { Check, ChevronDown, ChevronUp } from "lucide-react" + +import { cn } from "@/lib/utils" + +const Select = SelectPrimitive.Root + +const SelectGroup = SelectPrimitive.Group + +const SelectValue = SelectPrimitive.Value + +const SelectTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + span]:line-clamp-1", + className + )} + {...props} + > + {children} + + + + +)) +SelectTrigger.displayName = SelectPrimitive.Trigger.displayName + +const SelectScrollUpButton = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName + +const SelectScrollDownButton = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +SelectScrollDownButton.displayName = + SelectPrimitive.ScrollDownButton.displayName + +const SelectContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, position = "popper", ...props }, ref) => ( + + + + + {children} + + + + +)) +SelectContent.displayName = SelectPrimitive.Content.displayName + +const SelectLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SelectLabel.displayName = SelectPrimitive.Label.displayName + +const SelectItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + + {children} + +)) +SelectItem.displayName = SelectPrimitive.Item.displayName + +const SelectSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SelectSeparator.displayName = SelectPrimitive.Separator.displayName + +export { + Select, + SelectGroup, + SelectValue, + SelectTrigger, + SelectContent, + SelectLabel, + SelectItem, + SelectSeparator, + SelectScrollUpButton, + SelectScrollDownButton, +} diff --git a/web/client-v2/src/constant/navigation.ts b/web/client-v2/src/constant/navigation.ts new file mode 100644 index 00000000..a0755d9b --- /dev/null +++ b/web/client-v2/src/constant/navigation.ts @@ -0,0 +1,13 @@ +export const NAVIGATION_LISTS = { + HOME: "/", + DASHBOARD_TREND: "/dashboard/trend", + DASHBOARD_SITE: "/dashboard/site", + DASHBOARD_COMPANY: "/dashboard/company", + DASHBOARD_SUMMARY: "/dashboard/summary", + BOOKMARK: "/bookmark", + ARTICLE_SEARCH: "/article/search", + ARTICLE_SEARCH_RESULT: "/article/search/result", + FEED: "/feed", + MY_FEED_FOLDER: "/my-feed", + FAVORITE_ARTICLE_FOLDER: "/favorite", +}; diff --git a/web/client-v2/src/features/articles/components/Tab/SelectArticlePageTab/SelectArticlePageTab.tsx b/web/client-v2/src/features/articles/components/Tab/SelectArticlePageTab/SelectArticlePageTab.tsx new file mode 100644 index 00000000..92e383cd --- /dev/null +++ b/web/client-v2/src/features/articles/components/Tab/SelectArticlePageTab/SelectArticlePageTab.tsx @@ -0,0 +1,92 @@ +"use client"; + +import { useRouter, usePathname } from "next/navigation"; +import { FC, useCallback, useMemo } from "react"; + +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; + +import { NAVIGATION_LISTS } from "@/constant/navigation"; + +type SelectArticlePageTabProps = { + userId?: string; +}; + +export const SelectArticlePageTab: FC = ({ + userId, +}) => { + const router = useRouter(); + const pathname = usePathname(); + + const defaultTabValue = useMemo(() => { + switch (pathname) { + case NAVIGATION_LISTS.DASHBOARD_TREND: + return "0"; + case NAVIGATION_LISTS.DASHBOARD_SITE: + return "1"; + case NAVIGATION_LISTS.DASHBOARD_COMPANY: + return "2"; + case NAVIGATION_LISTS.DASHBOARD_SUMMARY: + return "3"; + } + }, [pathname]); + + const onMovePage = useCallback( + (value: string) => { + switch (value) { + case "0": + if (userId) { + router.replace("/dashboard/trend"); + break; + } + break; + case "1": + if (userId) { + router.replace("/dashboard/site"); + break; + } + break; + case "2": + if (userId) { + router.replace("/dashboard/company"); + break; + } + break; + case "3": + if (userId) { + router.replace("/dashboard/summary"); + break; + } + break; + } + }, + [router, userId] + ); + + return ( + + ); +}; diff --git a/web/client-v2/src/features/articles/components/Tab/SelectArticlePageTab/index.ts b/web/client-v2/src/features/articles/components/Tab/SelectArticlePageTab/index.ts new file mode 100644 index 00000000..8c63c335 --- /dev/null +++ b/web/client-v2/src/features/articles/components/Tab/SelectArticlePageTab/index.ts @@ -0,0 +1 @@ +export * from "./SelectArticlePageTab"; diff --git a/web/client-v2/src/features/articles/components/Tab/index.ts b/web/client-v2/src/features/articles/components/Tab/index.ts new file mode 100644 index 00000000..8c63c335 --- /dev/null +++ b/web/client-v2/src/features/articles/components/Tab/index.ts @@ -0,0 +1 @@ +export * from "./SelectArticlePageTab"; diff --git a/web/client-v2/src/features/articles/components/Template/ArticleDashboardTemplate/ArticleDashboardTemplate.tsx b/web/client-v2/src/features/articles/components/Template/ArticleDashboardTemplate/ArticleDashboardTemplate.tsx index 8c9aa8d2..c9456919 100644 --- a/web/client-v2/src/features/articles/components/Template/ArticleDashboardTemplate/ArticleDashboardTemplate.tsx +++ b/web/client-v2/src/features/articles/components/Template/ArticleDashboardTemplate/ArticleDashboardTemplate.tsx @@ -15,6 +15,7 @@ import { ENGLISH_IMAGE, JAPANESE_IMAGE } from "@/constant/image"; import { ArticlesInput, FavoriteArticleFoldersInput } from "@/graphql/type"; import { ArticleDashboardTemplateQuery } from "./ArticleDashboardTemplateQuery"; +import { SelectArticlePageTab } from "../../Tab"; type ArticleDashboardTemplateProps = { user: User; @@ -56,7 +57,7 @@ export const ArticleDashboardTemplate: FC<

{title}

- {/* */} +
diff --git a/web/client-v2/src/features/trends/components/Template/TrendArticleDashboardTemplate/TrendArticleDashboardTemplate.tsx b/web/client-v2/src/features/trends/components/Template/TrendArticleDashboardTemplate/TrendArticleDashboardTemplate.tsx index 5395d01b..d3635d41 100644 --- a/web/client-v2/src/features/trends/components/Template/TrendArticleDashboardTemplate/TrendArticleDashboardTemplate.tsx +++ b/web/client-v2/src/features/trends/components/Template/TrendArticleDashboardTemplate/TrendArticleDashboardTemplate.tsx @@ -2,6 +2,8 @@ import { User } from "@supabase/supabase-js"; import Image from "next/image"; import { FC, Suspense } from "react"; +import { SelectArticlePageTab } from "@/features/articles/components/Tab"; + import { ScreenLoader } from "@/components/layout/ScreenLoader"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; @@ -53,7 +55,7 @@ export const TrendArticleDashboardTemplate: FC<

{title}

- {/* */} +
From 01defb419ed8137b556b2d6d4b0d08d1401aa555 Mon Sep 17 00:00:00 2001 From: YukiOnishi <58220747+YukiOnishi1129@users.noreply.github.com> Date: Sat, 4 Jan 2025 16:10:34 +0900 Subject: [PATCH 03/19] mobile header --- .../src/components/layout/Header/Header.tsx | 11 +-- .../Header/MobileHeader/MobileHeader.tsx | 68 +++++++++++++++++++ .../MobileHeader/MobileHeaderButton.tsx | 53 +++++++++++++++ .../layout/Header/MobileHeader/index.ts | 1 + web/client-v2/src/constant/navigation.ts | 2 + ...CreateFavoriteArticleDialogFloatButton.tsx | 40 +++++++++++ .../index.ts | 1 + .../favorites/components/Dialog/index.ts | 1 + 8 files changed, 168 insertions(+), 9 deletions(-) create mode 100644 web/client-v2/src/components/layout/Header/MobileHeader/MobileHeader.tsx create mode 100644 web/client-v2/src/components/layout/Header/MobileHeader/MobileHeaderButton.tsx create mode 100644 web/client-v2/src/components/layout/Header/MobileHeader/index.ts create mode 100644 web/client-v2/src/features/favorites/components/Dialog/CreateFavoriteArticleDialogFloatButton/CreateFavoriteArticleDialogFloatButton.tsx create mode 100644 web/client-v2/src/features/favorites/components/Dialog/CreateFavoriteArticleDialogFloatButton/index.ts diff --git a/web/client-v2/src/components/layout/Header/Header.tsx b/web/client-v2/src/components/layout/Header/Header.tsx index 515d8d2e..06bf460f 100644 --- a/web/client-v2/src/components/layout/Header/Header.tsx +++ b/web/client-v2/src/components/layout/Header/Header.tsx @@ -1,9 +1,8 @@ -"use client"; - import { User } from "@supabase/supabase-js"; import { FC } from "react"; import { DesktopHeader } from "./DesktopHeader"; +import { MobileHeader } from "./MobileHeader"; type HeaderProps = { user?: User; @@ -16,13 +15,7 @@ export const Header: FC = ({ user }) => {
- {/* */} +
); diff --git a/web/client-v2/src/components/layout/Header/MobileHeader/MobileHeader.tsx b/web/client-v2/src/components/layout/Header/MobileHeader/MobileHeader.tsx new file mode 100644 index 00000000..bab80cf2 --- /dev/null +++ b/web/client-v2/src/components/layout/Header/MobileHeader/MobileHeader.tsx @@ -0,0 +1,68 @@ +"use client"; + +import { User } from "@supabase/supabase-js"; +import { usePathname } from "next/navigation"; +import { FC, useMemo } from "react"; + +import { NAVIGATION_LISTS } from "@/constant/navigation"; + +import { MobileHeaderButton } from "./MobileHeaderButton"; + +type MobileHeaderProps = { + user?: User; +}; + +export const MobileHeader: FC = ({ user }) => { + const pathname = usePathname(); + + const pageName = useMemo(() => { + switch (pathname) { + case NAVIGATION_LISTS.DASHBOARD_TREND: + return "Trend"; + case NAVIGATION_LISTS.DASHBOARD_SITE: + return "Site"; + case NAVIGATION_LISTS.DASHBOARD_COMPANY: + return "Company"; + case NAVIGATION_LISTS.DASHBOARD_SUMMARY: + return "Summary"; + case NAVIGATION_LISTS.BOOKMARK: + return "Bookmark"; + case NAVIGATION_LISTS.ARTICLE_SEARCH: + return "Search"; + case NAVIGATION_LISTS.ARTICLE_SEARCH_RESULT: + return "Search Result"; + case NAVIGATION_LISTS.FEED: + return "Feeds"; + case NAVIGATION_LISTS.MY_FEED_FOLDER: + return "My Feed Folders"; + case NAVIGATION_LISTS.FAVORITE_ARTICLE_FOLDER: + return "Favorite Article Folders"; + default: + if (pathname.includes(NAVIGATION_LISTS.MY_FEED_FOLDER_ARTICLE)) { + return "My Feed Articles"; + } + if ( + pathname.includes(NAVIGATION_LISTS.FAVORITE_ARTICLE_FOLDER_ARTICLE) + ) { + return "Favorite Articles"; + } + return "Check Picks"; + } + }, [pathname]); + + return ( +
+
+ {/* */} +
+ +

{pageName}

+
+ +
+
+ ); +}; diff --git a/web/client-v2/src/components/layout/Header/MobileHeader/MobileHeaderButton.tsx b/web/client-v2/src/components/layout/Header/MobileHeader/MobileHeaderButton.tsx new file mode 100644 index 00000000..ed316a25 --- /dev/null +++ b/web/client-v2/src/components/layout/Header/MobileHeader/MobileHeaderButton.tsx @@ -0,0 +1,53 @@ +"use client"; + +import { User } from "@supabase/supabase-js"; +import { useParams } from "next/navigation"; +import { FC, useMemo } from "react"; + +import { CreateBookmarkDialog } from "@/features/bookmarks/components/Dialog"; +import { + CreateFavoriteArticleFolderDialog, + CreateFavoriteArticleDialogFloatButton, +} from "@/features/favorites/components/Dialog"; +import { CreateMyFeedFolderDialog } from "@/features/myFeeds/components/Dialog"; + +import { NAVIGATION_LISTS } from "@/constant/navigation"; + +type MobileHeaderButtonProps = { + user?: User; + pathname: string; +}; + +export const MobileHeaderButton: FC = ({ + user, + pathname, +}) => { + const params = useParams(); + const targetId = params.id; + + const headerButton = useMemo(() => { + switch (pathname) { + case NAVIGATION_LISTS.BOOKMARK: + return ; + case NAVIGATION_LISTS.MY_FEED_FOLDER: + return ; + case NAVIGATION_LISTS.FAVORITE_ARTICLE_FOLDER: + return ; + default: + if ( + pathname.includes(NAVIGATION_LISTS.FAVORITE_ARTICLE_FOLDER_ARTICLE) && + typeof targetId === "string" + ) { + return ( + + ); + } + return <>; + } + }, [pathname, user, targetId]); + + return <>{headerButton}; +}; diff --git a/web/client-v2/src/components/layout/Header/MobileHeader/index.ts b/web/client-v2/src/components/layout/Header/MobileHeader/index.ts new file mode 100644 index 00000000..1a122d8f --- /dev/null +++ b/web/client-v2/src/components/layout/Header/MobileHeader/index.ts @@ -0,0 +1 @@ +export * from "./MobileHeader"; diff --git a/web/client-v2/src/constant/navigation.ts b/web/client-v2/src/constant/navigation.ts index a0755d9b..0ec2cd06 100644 --- a/web/client-v2/src/constant/navigation.ts +++ b/web/client-v2/src/constant/navigation.ts @@ -9,5 +9,7 @@ export const NAVIGATION_LISTS = { ARTICLE_SEARCH_RESULT: "/article/search/result", FEED: "/feed", MY_FEED_FOLDER: "/my-feed", + MY_FEED_FOLDER_ARTICLE: "/my-feed/article", FAVORITE_ARTICLE_FOLDER: "/favorite", + FAVORITE_ARTICLE_FOLDER_ARTICLE: "/favorite/article", }; diff --git a/web/client-v2/src/features/favorites/components/Dialog/CreateFavoriteArticleDialogFloatButton/CreateFavoriteArticleDialogFloatButton.tsx b/web/client-v2/src/features/favorites/components/Dialog/CreateFavoriteArticleDialogFloatButton/CreateFavoriteArticleDialogFloatButton.tsx new file mode 100644 index 00000000..7e914a5e --- /dev/null +++ b/web/client-v2/src/features/favorites/components/Dialog/CreateFavoriteArticleDialogFloatButton/CreateFavoriteArticleDialogFloatButton.tsx @@ -0,0 +1,40 @@ +"use client"; + +import { User } from "@supabase/supabase-js"; +import { useState, FC, useCallback } from "react"; +import { HiPlus } from "react-icons/hi"; + +import { Button } from "@/components/ui/button"; +import { Dialog, DialogTrigger } from "@/components/ui/dialog"; + +import { CreateFavoriteArticleDialogContent } from "../CreateFavoriteArticleDialog/CreateFavoriteArticleDialogContent"; + +type CreateFavoriteArticleDialogFloatButtonProps = { + user: User | undefined; + favoriteArticleFolderId: string; +}; + +export const CreateFavoriteArticleDialogFloatButton: FC< + CreateFavoriteArticleDialogFloatButtonProps +> = ({ user, favoriteArticleFolderId }) => { + const [open, setOpen] = useState(false); + + const handleClose = useCallback(() => setOpen(false), []); + + return ( + + + + + {open && ( + + )} + + ); +}; diff --git a/web/client-v2/src/features/favorites/components/Dialog/CreateFavoriteArticleDialogFloatButton/index.ts b/web/client-v2/src/features/favorites/components/Dialog/CreateFavoriteArticleDialogFloatButton/index.ts new file mode 100644 index 00000000..ee5526d6 --- /dev/null +++ b/web/client-v2/src/features/favorites/components/Dialog/CreateFavoriteArticleDialogFloatButton/index.ts @@ -0,0 +1 @@ +export * from "./CreateFavoriteArticleDialogFloatButton"; diff --git a/web/client-v2/src/features/favorites/components/Dialog/index.ts b/web/client-v2/src/features/favorites/components/Dialog/index.ts index 2d3af281..80cc72e8 100644 --- a/web/client-v2/src/features/favorites/components/Dialog/index.ts +++ b/web/client-v2/src/features/favorites/components/Dialog/index.ts @@ -4,3 +4,4 @@ export * from "./DeleteFavoriteArticleFolderAlertDialog"; export * from "./RemoveFavoriteArticleAlertDialog"; export * from "./CreateFavoriteArticleDialog"; +export * from "./CreateFavoriteArticleDialogFloatButton"; From f1b46179940d7683ded962d552300920f4548dec Mon Sep 17 00:00:00 2001 From: YukiOnishi <58220747+YukiOnishi1129@users.noreply.github.com> Date: Sat, 4 Jan 2025 16:15:01 +0900 Subject: [PATCH 04/19] side navigation --- web/client-v2/package-lock.json | 283 +++++++++++++++++- web/client-v2/package.json | 2 +- .../Header/MobileHeader/MobileHeader.tsx | 6 +- .../MobileSidebarNavigation.tsx | 30 ++ .../MobileSidebarNavigationContent.tsx | 24 ++ .../MobileSidebarNavigation/index.ts | 1 + web/client-v2/src/components/ui/sheet.tsx | 140 +++++++++ 7 files changed, 466 insertions(+), 20 deletions(-) create mode 100644 web/client-v2/src/components/layout/Header/MobileHeader/MobileSidebarNavigation/MobileSidebarNavigation.tsx create mode 100644 web/client-v2/src/components/layout/Header/MobileHeader/MobileSidebarNavigation/MobileSidebarNavigationContent.tsx create mode 100644 web/client-v2/src/components/layout/Header/MobileHeader/MobileSidebarNavigation/index.ts create mode 100644 web/client-v2/src/components/ui/sheet.tsx diff --git a/web/client-v2/package-lock.json b/web/client-v2/package-lock.json index c2ec11b6..201927b8 100644 --- a/web/client-v2/package-lock.json +++ b/web/client-v2/package-lock.json @@ -15,7 +15,7 @@ "@radix-ui/react-alert-dialog": "^1.1.1", "@radix-ui/react-avatar": "^1.1.0", "@radix-ui/react-checkbox": "^1.1.3", - "@radix-ui/react-dialog": "^1.1.1", + "@radix-ui/react-dialog": "^1.1.4", "@radix-ui/react-dropdown-menu": "^2.1.1", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-label": "^2.1.0", @@ -4160,6 +4160,42 @@ } } }, + "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-dialog": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.1.tgz", + "integrity": "sha512-zysS+iU4YP3STKNS6USvFVqI4qqx8EpiwmT5TuCApVEBca+eRCbONi4EgzfNSuVnOXvC5UPHHMjs8RXO6DH9Bg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-focus-guards": "1.1.0", + "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-portal": "1.1.1", + "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.7" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-arrow": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz", @@ -4528,25 +4564,88 @@ } }, "node_modules/@radix-ui/react-dialog": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.1.tgz", - "integrity": "sha512-zysS+iU4YP3STKNS6USvFVqI4qqx8EpiwmT5TuCApVEBca+eRCbONi4EgzfNSuVnOXvC5UPHHMjs8RXO6DH9Bg==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.4.tgz", + "integrity": "sha512-Ur7EV1IwQGCyaAuyDRiOLA5JIUZxELJljF+MbM/2NC0BYwfuRrbpS30BiQBJrVruscgUkieKkqXYDOoByaxIoA==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-dismissable-layer": "1.1.0", - "@radix-ui/react-focus-guards": "1.1.0", - "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.3", + "@radix-ui/react-focus-guards": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.1", "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-portal": "1.1.1", - "@radix-ui/react-presence": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-portal": "1.1.3", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-slot": "1.1.1", "@radix-ui/react-use-controllable-state": "1.1.0", "aria-hidden": "^1.1.1", - "react-remove-scroll": "2.5.7" + "react-remove-scroll": "^2.6.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", + "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", + "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-context": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz", + "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.3.tgz", + "integrity": "sha512-onrWn/72lQoEucDmJnr8uczSNTujT0vJnA/X5+3AkChVPowr8n1yvIKIabhWyMQeMvvmdpsvcyDqx3X1LEXCPg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-escape-keydown": "1.1.0" }, "peerDependencies": { "@types/react": "*", @@ -4563,6 +4662,160 @@ } } }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz", + "integrity": "sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.1.tgz", + "integrity": "sha512-01omzJAYRxXdG2/he/+xy+c8a8gCydoQ1yOxnWNcRhrrBW5W+RQJ22EK1SaO8tb3WoUsuEw7mJjBozPzihDFjA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-portal": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.3.tgz", + "integrity": "sha512-NciRqhXnGojhT93RPyDaMPfLH3ZSl4jjIFbZQ1b/vxvZEdHsBZ49wP9w8L3HzUQwep01LcWtkUvm0OVB5JAHTw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-presence": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz", + "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-primitive": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz", + "integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz", + "integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/react-remove-scroll": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.2.tgz", + "integrity": "sha512-KmONPx5fnlXYJQqC62Q+lwIeAk64ws/cUw6omIumRzMRPqgnYqhSSti99nbj0Ry13bv7dF+BKn7NB+OqkdZGTw==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.1", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-direction": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz", diff --git a/web/client-v2/package.json b/web/client-v2/package.json index b550013b..a500b807 100644 --- a/web/client-v2/package.json +++ b/web/client-v2/package.json @@ -21,7 +21,7 @@ "@radix-ui/react-alert-dialog": "^1.1.1", "@radix-ui/react-avatar": "^1.1.0", "@radix-ui/react-checkbox": "^1.1.3", - "@radix-ui/react-dialog": "^1.1.1", + "@radix-ui/react-dialog": "^1.1.4", "@radix-ui/react-dropdown-menu": "^2.1.1", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-label": "^2.1.0", diff --git a/web/client-v2/src/components/layout/Header/MobileHeader/MobileHeader.tsx b/web/client-v2/src/components/layout/Header/MobileHeader/MobileHeader.tsx index bab80cf2..48e13cbc 100644 --- a/web/client-v2/src/components/layout/Header/MobileHeader/MobileHeader.tsx +++ b/web/client-v2/src/components/layout/Header/MobileHeader/MobileHeader.tsx @@ -7,6 +7,7 @@ import { FC, useMemo } from "react"; import { NAVIGATION_LISTS } from "@/constant/navigation"; import { MobileHeaderButton } from "./MobileHeaderButton"; +import { MobileSidebarNavigation } from "./MobileSidebarNavigation"; type MobileHeaderProps = { user?: User; @@ -53,10 +54,7 @@ export const MobileHeader: FC = ({ user }) => { return (
- {/* */} +

{pageName}

diff --git a/web/client-v2/src/components/layout/Header/MobileHeader/MobileSidebarNavigation/MobileSidebarNavigation.tsx b/web/client-v2/src/components/layout/Header/MobileHeader/MobileSidebarNavigation/MobileSidebarNavigation.tsx new file mode 100644 index 00000000..89d40f16 --- /dev/null +++ b/web/client-v2/src/components/layout/Header/MobileHeader/MobileSidebarNavigation/MobileSidebarNavigation.tsx @@ -0,0 +1,30 @@ +"use client"; + +import { FC, useCallback, useState } from "react"; +import { HiOutlineMenuAlt2 } from "react-icons/hi"; + +import { Sheet, SheetTrigger } from "@/components/ui/sheet"; + +import { MobileSidebarNavigationContent } from "./MobileSidebarNavigationContent"; + +type MobileSidebarNavigationProps = {}; + +export const MobileSidebarNavigation: FC = () => { + const [open, setOpen] = useState(false); + + const handleCloseSheet = useCallback(() => { + setOpen(false); + }, []); + + return ( + + + + + + {open && ( + + )} + + ); +}; diff --git a/web/client-v2/src/components/layout/Header/MobileHeader/MobileSidebarNavigation/MobileSidebarNavigationContent.tsx b/web/client-v2/src/components/layout/Header/MobileHeader/MobileSidebarNavigation/MobileSidebarNavigationContent.tsx new file mode 100644 index 00000000..45e8febd --- /dev/null +++ b/web/client-v2/src/components/layout/Header/MobileHeader/MobileSidebarNavigation/MobileSidebarNavigationContent.tsx @@ -0,0 +1,24 @@ +"use client"; + +import { FC } from "react"; + +// import { MobileSidebar } from "@/components/layout/Sidebar/MobileSidebar"; +import { SheetContent } from "@/components/ui/sheet"; + +type MobileSidebarNavigationContentProps = { + onCloseSheet: () => void; +}; + +export const MobileSidebarNavigationContent: FC< + MobileSidebarNavigationContentProps +> = ({ onCloseSheet }) => { + return ( + + {/* */} + + ); +}; diff --git a/web/client-v2/src/components/layout/Header/MobileHeader/MobileSidebarNavigation/index.ts b/web/client-v2/src/components/layout/Header/MobileHeader/MobileSidebarNavigation/index.ts new file mode 100644 index 00000000..4eae829e --- /dev/null +++ b/web/client-v2/src/components/layout/Header/MobileHeader/MobileSidebarNavigation/index.ts @@ -0,0 +1 @@ +export * from "./MobileSidebarNavigation"; diff --git a/web/client-v2/src/components/ui/sheet.tsx b/web/client-v2/src/components/ui/sheet.tsx new file mode 100644 index 00000000..a37f17ba --- /dev/null +++ b/web/client-v2/src/components/ui/sheet.tsx @@ -0,0 +1,140 @@ +"use client" + +import * as React from "react" +import * as SheetPrimitive from "@radix-ui/react-dialog" +import { cva, type VariantProps } from "class-variance-authority" +import { X } from "lucide-react" + +import { cn } from "@/lib/utils" + +const Sheet = SheetPrimitive.Root + +const SheetTrigger = SheetPrimitive.Trigger + +const SheetClose = SheetPrimitive.Close + +const SheetPortal = SheetPrimitive.Portal + +const SheetOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SheetOverlay.displayName = SheetPrimitive.Overlay.displayName + +const sheetVariants = cva( + "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500", + { + variants: { + side: { + top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top", + bottom: + "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom", + left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm", + right: + "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm", + }, + }, + defaultVariants: { + side: "right", + }, + } +) + +interface SheetContentProps + extends React.ComponentPropsWithoutRef, + VariantProps {} + +const SheetContent = React.forwardRef< + React.ElementRef, + SheetContentProps +>(({ side = "right", className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)) +SheetContent.displayName = SheetPrimitive.Content.displayName + +const SheetHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +SheetHeader.displayName = "SheetHeader" + +const SheetFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +SheetFooter.displayName = "SheetFooter" + +const SheetTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SheetTitle.displayName = SheetPrimitive.Title.displayName + +const SheetDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SheetDescription.displayName = SheetPrimitive.Description.displayName + +export { + Sheet, + SheetPortal, + SheetOverlay, + SheetTrigger, + SheetClose, + SheetContent, + SheetHeader, + SheetFooter, + SheetTitle, + SheetDescription, +} From 27e9baa652f41a75758222304f837df2bf76e16c Mon Sep 17 00:00:00 2001 From: YukiOnishi <58220747+YukiOnishi1129@users.noreply.github.com> Date: Sat, 4 Jan 2025 16:20:50 +0900 Subject: [PATCH 05/19] mobile sidebar --- .../MobileSidebarNavigationContent.tsx | 8 +- .../Sidebar/DesktopSidebar/DesktopSidebar.tsx | 8 - .../Sidebar/MobileSidebar/MobileSidebar.tsx | 165 ++++++++++++++++++ .../layout/Sidebar/MobileSidebar/index.ts | 1 + .../src/components/layout/Sidebar/index.ts | 4 +- 5 files changed, 171 insertions(+), 15 deletions(-) create mode 100644 web/client-v2/src/components/layout/Sidebar/MobileSidebar/MobileSidebar.tsx create mode 100644 web/client-v2/src/components/layout/Sidebar/MobileSidebar/index.ts diff --git a/web/client-v2/src/components/layout/Header/MobileHeader/MobileSidebarNavigation/MobileSidebarNavigationContent.tsx b/web/client-v2/src/components/layout/Header/MobileHeader/MobileSidebarNavigation/MobileSidebarNavigationContent.tsx index 45e8febd..15cd6e40 100644 --- a/web/client-v2/src/components/layout/Header/MobileHeader/MobileSidebarNavigation/MobileSidebarNavigationContent.tsx +++ b/web/client-v2/src/components/layout/Header/MobileHeader/MobileSidebarNavigation/MobileSidebarNavigationContent.tsx @@ -2,7 +2,7 @@ import { FC } from "react"; -// import { MobileSidebar } from "@/components/layout/Sidebar/MobileSidebar"; +import { MobileSidebar } from "@/components/layout/Sidebar"; import { SheetContent } from "@/components/ui/sheet"; type MobileSidebarNavigationContentProps = { @@ -14,11 +14,7 @@ export const MobileSidebarNavigationContent: FC< > = ({ onCloseSheet }) => { return ( - {/* */} + ); }; diff --git a/web/client-v2/src/components/layout/Sidebar/DesktopSidebar/DesktopSidebar.tsx b/web/client-v2/src/components/layout/Sidebar/DesktopSidebar/DesktopSidebar.tsx index 2af18681..1b9e317f 100644 --- a/web/client-v2/src/components/layout/Sidebar/DesktopSidebar/DesktopSidebar.tsx +++ b/web/client-v2/src/components/layout/Sidebar/DesktopSidebar/DesktopSidebar.tsx @@ -11,13 +11,6 @@ import { MdRssFeed, } from "react-icons/md"; -// import { CreateFavoriteArticleFolderDialog } from "@/features/favoriteArticleFolders/components/Dialog"; -// import { CreateMyFeedFolderDialog } from "@/features/myFeedFolders/components/Dialog"; - -// import { FavoriteArticleFolderType } from "@/types/favoriteArticleFolder"; -// import { MyFeedFolderType } from "@/types/myFeedFolder"; - -// import { FavoriteArticleFolderLinks } from "./FavoriteArticleFolderLinks"; import { CreateFavoriteArticleFolderDialog } from "@/features/favorites/components/Dialog"; import { CreateMyFeedFolderDialog } from "@/features/myFeeds/components/Dialog"; @@ -26,7 +19,6 @@ import { LoggedBaseLayoutQuery } from "@/components/layout/BaseLayout/LoggedBase import { FavoriteArticleFolderLink } from "../FavoriteArticleFolderLink"; import { LogoutLink } from "../LogoutLink"; import { MyFeedFolderLink } from "../MyFeedFolderLink"; -// import { MyFeedFolderLinks } from "./MyFeedFolderLinks"; export function DesktopSidebar() { const { data: resSuspenseData, error } = useSuspenseQuery( diff --git a/web/client-v2/src/components/layout/Sidebar/MobileSidebar/MobileSidebar.tsx b/web/client-v2/src/components/layout/Sidebar/MobileSidebar/MobileSidebar.tsx new file mode 100644 index 00000000..15ab2449 --- /dev/null +++ b/web/client-v2/src/components/layout/Sidebar/MobileSidebar/MobileSidebar.tsx @@ -0,0 +1,165 @@ +"use client"; + +import Link from "next/link"; +import { FC } from "react"; +import { CgWebsite } from "react-icons/cg"; +import { FaRegBookmark } from "react-icons/fa"; +import { + MdFeed, + MdRssFeed, + MdOutlineStarOutline, + MdBusiness, + MdOutlineSummarize, +} from "react-icons/md"; + +import { CreateFavoriteArticleFolderDialog } from "@/features/favorites/components/Dialog"; +import { CreateMyFeedFolderDialog } from "@/features/myFeeds/components/Dialog"; + +import { LogoutLink } from "../LogoutLink"; + +type SidebarProps = { + // myFeedFolders: Array; + // favoriteArticleFolders: Array; + onCloseSheet: () => void; +}; + +export const MobileSidebar: FC = ({ onCloseSheet }) => { + return ( +
+
+
+

+ Main +

+
+ + + Trend + + + + Site + + + + Company + + + + Summary + + + + + Bookmarks + + + + + Feeds + + + {/* + + Search + */} +
+
+ + <> +
+

+ My Feeds +

+
+ + + All + + {/* */} +
+ +
+
+
+ +
+

+ Favorite Articles +

+
+ + + Folders + + + + All + + {/* */} +
+ +
+
+
+ + +
+ +
+
+
+ ); +}; diff --git a/web/client-v2/src/components/layout/Sidebar/MobileSidebar/index.ts b/web/client-v2/src/components/layout/Sidebar/MobileSidebar/index.ts new file mode 100644 index 00000000..64d6d58e --- /dev/null +++ b/web/client-v2/src/components/layout/Sidebar/MobileSidebar/index.ts @@ -0,0 +1 @@ +export * from "./MobileSidebar"; diff --git a/web/client-v2/src/components/layout/Sidebar/index.ts b/web/client-v2/src/components/layout/Sidebar/index.ts index 26b8d935..138fa40c 100644 --- a/web/client-v2/src/components/layout/Sidebar/index.ts +++ b/web/client-v2/src/components/layout/Sidebar/index.ts @@ -1 +1,3 @@ -export * from "./DesktopSidebar/DesktopSidebar"; +export * from "./DesktopSidebar"; + +export * from "./MobileSidebar"; From 35a03b1e1e9caaed50344af89f0ca10eda734bb7 Mon Sep 17 00:00:00 2001 From: YukiOnishi <58220747+YukiOnishi1129@users.noreply.github.com> Date: Sat, 4 Jan 2025 16:28:48 +0900 Subject: [PATCH 06/19] mobile side bar --- .../MobileSidebar/GetMobileSidebarQuery.ts | 30 +++++++++ .../Sidebar/MobileSidebar/MobileSidebar.tsx | 46 +++++++++++--- web/client-v2/src/components/ui/select.tsx | 12 ++-- web/client-v2/src/components/ui/sheet.tsx | 6 +- web/client-v2/src/graphql/type.ts | 62 +++++++++++++++++++ 5 files changed, 137 insertions(+), 19 deletions(-) create mode 100644 web/client-v2/src/components/layout/Sidebar/MobileSidebar/GetMobileSidebarQuery.ts diff --git a/web/client-v2/src/components/layout/Sidebar/MobileSidebar/GetMobileSidebarQuery.ts b/web/client-v2/src/components/layout/Sidebar/MobileSidebar/GetMobileSidebarQuery.ts new file mode 100644 index 00000000..485823df --- /dev/null +++ b/web/client-v2/src/components/layout/Sidebar/MobileSidebar/GetMobileSidebarQuery.ts @@ -0,0 +1,30 @@ +import { graphql } from "gql.tada"; + +import { FavoriteArticleFolderLinkFragment } from "../FavoriteArticleFolderLink/FavoriteArticleFolderLinkFragment"; +import { MyFeedFolderLinkFragment } from "../MyFeedFolderLink/MyFeedFolderLinkFragment"; + +export const GetMobileSidebarQuery = graphql( + ` + query GetMobileSidebarQuery( + $input: FavoriteArticleFoldersInput! + $myFeedFoldersInput: MyFeedFoldersInput! + ) { + favoriteArticleFolders(input: $input) { + edges { + node { + ...FavoriteArticleFolderLinkFragment + } + } + } + myFeedFolders(myFeedFoldersInput: $myFeedFoldersInput) { + edges { + node { + id + ...MyFeedFolderLinkFragment + } + } + } + } + `, + [FavoriteArticleFolderLinkFragment, MyFeedFolderLinkFragment] +); diff --git a/web/client-v2/src/components/layout/Sidebar/MobileSidebar/MobileSidebar.tsx b/web/client-v2/src/components/layout/Sidebar/MobileSidebar/MobileSidebar.tsx index 15ab2449..6332ff9f 100644 --- a/web/client-v2/src/components/layout/Sidebar/MobileSidebar/MobileSidebar.tsx +++ b/web/client-v2/src/components/layout/Sidebar/MobileSidebar/MobileSidebar.tsx @@ -1,5 +1,6 @@ "use client"; +import { useQuery } from "@apollo/client"; import Link from "next/link"; import { FC } from "react"; import { CgWebsite } from "react-icons/cg"; @@ -15,15 +16,36 @@ import { import { CreateFavoriteArticleFolderDialog } from "@/features/favorites/components/Dialog"; import { CreateMyFeedFolderDialog } from "@/features/myFeeds/components/Dialog"; +import { GetMobileSidebarQuery } from "./GetMobileSidebarQuery"; +import { FavoriteArticleFolderLink } from "../FavoriteArticleFolderLink"; import { LogoutLink } from "../LogoutLink"; +import { MyFeedFolderLink } from "../MyFeedFolderLink"; type SidebarProps = { - // myFeedFolders: Array; - // favoriteArticleFolders: Array; onCloseSheet: () => void; }; export const MobileSidebar: FC = ({ onCloseSheet }) => { + const { data, loading, error } = useQuery(GetMobileSidebarQuery, { + variables: { + input: { + isAllFetch: true, + isFolderOnly: true, + }, + myFeedFoldersInput: { + isAllFetch: true, + }, + }, + }); + + if (loading) { + return
Loading...
; + } + + if (error) { + return
Error: {error.message}
; + } + return (
@@ -108,10 +130,12 @@ export const MobileSidebar: FC = ({ onCloseSheet }) => { All - {/* */} + {data?.myFeedFolders.edges.map((edge, i) => ( + + ))}
= ({ onCloseSheet }) => { All - {/* */} + {data?.favoriteArticleFolders.edges.map((edge, i) => ( + + ))}
{children} - + )) @@ -44,7 +44,7 @@ const SelectScrollUpButton = React.forwardRef< )} {...props} > - + )) SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName @@ -61,7 +61,7 @@ const SelectScrollDownButton = React.forwardRef< )} {...props} > - + )) SelectScrollDownButton.displayName = @@ -123,9 +123,9 @@ const SelectItem = React.forwardRef< )} {...props} > - + - + diff --git a/web/client-v2/src/components/ui/sheet.tsx b/web/client-v2/src/components/ui/sheet.tsx index a37f17ba..44518ebd 100644 --- a/web/client-v2/src/components/ui/sheet.tsx +++ b/web/client-v2/src/components/ui/sheet.tsx @@ -1,9 +1,9 @@ "use client" -import * as React from "react" import * as SheetPrimitive from "@radix-ui/react-dialog" import { cva, type VariantProps } from "class-variance-authority" import { X } from "lucide-react" +import * as React from "react" import { cn } from "@/lib/utils" @@ -31,7 +31,7 @@ const SheetOverlay = React.forwardRef< SheetOverlay.displayName = SheetPrimitive.Overlay.displayName const sheetVariants = cva( - "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500", + "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out", { variants: { side: { @@ -66,7 +66,7 @@ const SheetContent = React.forwardRef< > {children} - + Close diff --git a/web/client-v2/src/graphql/type.ts b/web/client-v2/src/graphql/type.ts index 3269f919..e5f148bd 100644 --- a/web/client-v2/src/graphql/type.ts +++ b/web/client-v2/src/graphql/type.ts @@ -634,6 +634,14 @@ export type FavoriteArticleFolderLinkFragmentFragment = { __typename?: 'Favorite export type FeedAccordionFragmentFragment = { __typename?: 'MyFeedFolder', id: string, feeds?: Array<{ __typename?: 'Feed', id: string, name: string, platform: { __typename?: 'Platform', faviconUrl: string } }> | null }; +export type GetMobileSidebarQueryQueryVariables = Exact<{ + input: FavoriteArticleFoldersInput; + myFeedFoldersInput: MyFeedFoldersInput; +}>; + + +export type GetMobileSidebarQueryQuery = { __typename?: 'Query', favoriteArticleFolders: { __typename?: 'FavoriteArticleFolderConnection', edges: Array<{ __typename?: 'FavoriteArticleFolderEdge', node: { __typename?: 'FavoriteArticleFolder', id: string, title: string } }> }, myFeedFolders: { __typename?: 'MyFeedFolderConnection', edges: Array<{ __typename?: 'MyFeedFolderEdge', node: { __typename?: 'MyFeedFolder', id: string, title: string, feeds?: Array<{ __typename?: 'Feed', id: string, name: string, platform: { __typename?: 'Platform', faviconUrl: string } }> | null } }> } }; + export type MyFeedFolderLinkFragmentFragment = { __typename?: 'MyFeedFolder', id: string, title: string, feeds?: Array<{ __typename?: 'Feed', id: string, name: string, platform: { __typename?: 'Platform', faviconUrl: string } }> | null }; export type ArticleCardItemFragmentFragment = { __typename?: 'Article', id: string, title: string, description: string, articleUrl: string, publishedAt?: number | null, thumbnailUrl: string, isEng: boolean, isPrivate: boolean, isBookmarked: boolean, bookmarkId?: string | null, likeCount?: number | null, platform?: { __typename?: 'Platform', id: string, name: string, siteUrl: string, faviconUrl: string } | null, feeds?: Array<{ __typename?: 'Feed', id: string, name: string }> | null }; @@ -1595,6 +1603,60 @@ export type GetLoggedBaseLayoutQueryQueryHookResult = ReturnType; export type GetLoggedBaseLayoutQuerySuspenseQueryHookResult = ReturnType; export type GetLoggedBaseLayoutQueryQueryResult = Apollo.QueryResult; +export const GetMobileSidebarQueryDocument = gql` + query GetMobileSidebarQuery($input: FavoriteArticleFoldersInput!, $myFeedFoldersInput: MyFeedFoldersInput!) { + favoriteArticleFolders(input: $input) { + edges { + node { + ...FavoriteArticleFolderLinkFragment + } + } + } + myFeedFolders(myFeedFoldersInput: $myFeedFoldersInput) { + edges { + node { + id + ...MyFeedFolderLinkFragment + } + } + } +} + ${FavoriteArticleFolderLinkFragmentFragmentDoc} +${MyFeedFolderLinkFragmentFragmentDoc}`; + +/** + * __useGetMobileSidebarQueryQuery__ + * + * To run a query within a React component, call `useGetMobileSidebarQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useGetMobileSidebarQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetMobileSidebarQueryQuery({ + * variables: { + * input: // value for 'input' + * myFeedFoldersInput: // value for 'myFeedFoldersInput' + * }, + * }); + */ +export function useGetMobileSidebarQueryQuery(baseOptions: Apollo.QueryHookOptions & ({ variables: GetMobileSidebarQueryQueryVariables; skip?: boolean; } | { skip: boolean; }) ) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(GetMobileSidebarQueryDocument, options); + } +export function useGetMobileSidebarQueryLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(GetMobileSidebarQueryDocument, options); + } +export function useGetMobileSidebarQuerySuspenseQuery(baseOptions?: Apollo.SuspenseQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useSuspenseQuery(GetMobileSidebarQueryDocument, options); + } +export type GetMobileSidebarQueryQueryHookResult = ReturnType; +export type GetMobileSidebarQueryLazyQueryHookResult = ReturnType; +export type GetMobileSidebarQuerySuspenseQueryHookResult = ReturnType; +export type GetMobileSidebarQueryQueryResult = Apollo.QueryResult; export const ArticleListQueryDocument = gql` query ArticleListQuery($input: ArticlesInput!) { articles(articlesInput: $input) { From b191aee8f5a5068bca7a9a78f5a00f96267f5072 Mon Sep 17 00:00:00 2001 From: YukiOnishi <58220747+YukiOnishi1129@users.noreply.github.com> Date: Sat, 4 Jan 2025 16:32:04 +0900 Subject: [PATCH 07/19] FeedKeywordSearchDialog --- .../FeedKeywordSearchDialog.tsx | 36 +++++++ .../FeedKeywordSearchDialogContent.tsx | 94 +++++++++++++++++++ .../Dialog/FeedKeywordSearchDialog/index.ts | 1 + .../features/feeds/components/Dialog/index.ts | 1 + .../FeedListTemplate/FeedListTemplate.tsx | 5 +- 5 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 web/client-v2/src/features/feeds/components/Dialog/FeedKeywordSearchDialog/FeedKeywordSearchDialog.tsx create mode 100644 web/client-v2/src/features/feeds/components/Dialog/FeedKeywordSearchDialog/FeedKeywordSearchDialogContent.tsx create mode 100644 web/client-v2/src/features/feeds/components/Dialog/FeedKeywordSearchDialog/index.ts create mode 100644 web/client-v2/src/features/feeds/components/Dialog/index.ts diff --git a/web/client-v2/src/features/feeds/components/Dialog/FeedKeywordSearchDialog/FeedKeywordSearchDialog.tsx b/web/client-v2/src/features/feeds/components/Dialog/FeedKeywordSearchDialog/FeedKeywordSearchDialog.tsx new file mode 100644 index 00000000..3e48f24c --- /dev/null +++ b/web/client-v2/src/features/feeds/components/Dialog/FeedKeywordSearchDialog/FeedKeywordSearchDialog.tsx @@ -0,0 +1,36 @@ +"use client"; + +import { FC, useCallback, useState } from "react"; +import { FaSearch } from "react-icons/fa"; + +import { Dialog, DialogTrigger } from "@/components/ui/dialog"; + +import { FeedKeywordSearchDialogContent } from "./FeedKeywordSearchDialogContent"; + +type FeedKeywordSearchDialogProps = { + keyword?: string; +}; + +export const FeedKeywordSearchDialog: FC = ({ + keyword, +}) => { + const [open, setOpen] = useState(false); + + const handleClose = useCallback(() => { + setOpen(false); + }, []); + + return ( + + + + + {open && ( + + )} + + ); +}; diff --git a/web/client-v2/src/features/feeds/components/Dialog/FeedKeywordSearchDialog/FeedKeywordSearchDialogContent.tsx b/web/client-v2/src/features/feeds/components/Dialog/FeedKeywordSearchDialog/FeedKeywordSearchDialogContent.tsx new file mode 100644 index 00000000..b948b4a3 --- /dev/null +++ b/web/client-v2/src/features/feeds/components/Dialog/FeedKeywordSearchDialog/FeedKeywordSearchDialogContent.tsx @@ -0,0 +1,94 @@ +"use client"; + +import { zodResolver } from "@hookform/resolvers/zod"; +import { usePathname, useRouter } from "next/navigation"; +import { FC, useCallback } from "react"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; + +import { + DialogContent, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { + Form, + FormField, + FormItem, + FormLabel, + FormControl, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; + +import { serverRevalidatePage } from "@/actions/actServerRevalidatePage"; + +const formSchema = z.object({ + keyword: z.string().optional(), +}); + +type FeedKeywordSearchDialogContentProps = { + keyword?: string; + handleClose: () => void; +}; + +export const FeedKeywordSearchDialogContent: FC< + FeedKeywordSearchDialogContentProps +> = ({ keyword, handleClose }) => { + const pathname = usePathname(); + const router = useRouter(); + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues: { + keyword: keyword ?? "", + }, + }); + + const resetDialog = useCallback(() => { + form.reset(); + }, [form]); + + const onSubmit = async (values: z.infer) => { + let keywordPath = ""; + if (!!values.keyword && values.keyword.trim() !== "") { + keywordPath = `keyword=${values.keyword}`; + } + await serverRevalidatePage(pathname); + router.replace(`/feed?${keywordPath}`); + resetDialog(); + handleClose(); + }; + + return ( + + + {"Search"} + +
+
+ +
+ ( + + Keyword + + + + + + )} + /> +
+
+ +
+
+ ); +}; diff --git a/web/client-v2/src/features/feeds/components/Dialog/FeedKeywordSearchDialog/index.ts b/web/client-v2/src/features/feeds/components/Dialog/FeedKeywordSearchDialog/index.ts new file mode 100644 index 00000000..f160749f --- /dev/null +++ b/web/client-v2/src/features/feeds/components/Dialog/FeedKeywordSearchDialog/index.ts @@ -0,0 +1 @@ +export * from "./FeedKeywordSearchDialog"; diff --git a/web/client-v2/src/features/feeds/components/Dialog/index.ts b/web/client-v2/src/features/feeds/components/Dialog/index.ts new file mode 100644 index 00000000..f160749f --- /dev/null +++ b/web/client-v2/src/features/feeds/components/Dialog/index.ts @@ -0,0 +1 @@ +export * from "./FeedKeywordSearchDialog"; diff --git a/web/client-v2/src/features/feeds/components/Template/FeedListTemplate/FeedListTemplate.tsx b/web/client-v2/src/features/feeds/components/Template/FeedListTemplate/FeedListTemplate.tsx index 7ef33c1b..43e7d52c 100644 --- a/web/client-v2/src/features/feeds/components/Template/FeedListTemplate/FeedListTemplate.tsx +++ b/web/client-v2/src/features/feeds/components/Template/FeedListTemplate/FeedListTemplate.tsx @@ -7,6 +7,7 @@ import { PreloadQuery } from "@/lib/apollo/client"; import { PlatformSiteType } from "@/types/platform"; import { FeedListTemplateQuery } from "./FeedListTemplateQuery"; +import { FeedKeywordSearchDialog } from "../../Dialog"; import { FeedList } from "../../List"; import { FeedKeywordSearchForm } from "../../Search"; @@ -53,9 +54,9 @@ export const FeedListTemplate: FC = ({ - {/*
+
-
*/} +
); }; From 05e53027e02fa63cbe23b847709ff69413bc206d Mon Sep 17 00:00:00 2001 From: YukiOnishi <58220747+YukiOnishi1129@users.noreply.github.com> Date: Sat, 4 Jan 2025 16:38:44 +0900 Subject: [PATCH 08/19] search --- .../FeedArticleKeywordSearchDialog.tsx | 38 ++++++++ .../FeedArticleKeywordSearchDialogContent.tsx | 95 +++++++++++++++++++ .../FeedArticleKeywordSearchDialog/index.ts | 1 + .../features/feeds/components/Dialog/index.ts | 1 + .../FeedArticleListTemplate.tsx | 5 + 5 files changed, 140 insertions(+) create mode 100644 web/client-v2/src/features/feeds/components/Dialog/FeedArticleKeywordSearchDialog/FeedArticleKeywordSearchDialog.tsx create mode 100644 web/client-v2/src/features/feeds/components/Dialog/FeedArticleKeywordSearchDialog/FeedArticleKeywordSearchDialogContent.tsx create mode 100644 web/client-v2/src/features/feeds/components/Dialog/FeedArticleKeywordSearchDialog/index.ts diff --git a/web/client-v2/src/features/feeds/components/Dialog/FeedArticleKeywordSearchDialog/FeedArticleKeywordSearchDialog.tsx b/web/client-v2/src/features/feeds/components/Dialog/FeedArticleKeywordSearchDialog/FeedArticleKeywordSearchDialog.tsx new file mode 100644 index 00000000..c4d8e49d --- /dev/null +++ b/web/client-v2/src/features/feeds/components/Dialog/FeedArticleKeywordSearchDialog/FeedArticleKeywordSearchDialog.tsx @@ -0,0 +1,38 @@ +"use client"; + +import { FC, useCallback, useState } from "react"; +import { FaSearch } from "react-icons/fa"; + +import { Dialog, DialogTrigger } from "@/components/ui/dialog"; + +import { FeedArticleKeywordSearchDialogContent } from "./FeedArticleKeywordSearchDialogContent"; + +type FeedArticleKeywordSearchDialogProps = { + feedId: string; + keyword?: string; +}; + +export const FeedArticleKeywordSearchDialog: FC< + FeedArticleKeywordSearchDialogProps +> = ({ feedId, keyword }) => { + const [open, setOpen] = useState(false); + + const handleClose = useCallback(() => { + setOpen(false); + }, []); + + return ( + + + + + {open && ( + + )} + + ); +}; diff --git a/web/client-v2/src/features/feeds/components/Dialog/FeedArticleKeywordSearchDialog/FeedArticleKeywordSearchDialogContent.tsx b/web/client-v2/src/features/feeds/components/Dialog/FeedArticleKeywordSearchDialog/FeedArticleKeywordSearchDialogContent.tsx new file mode 100644 index 00000000..d56a2d59 --- /dev/null +++ b/web/client-v2/src/features/feeds/components/Dialog/FeedArticleKeywordSearchDialog/FeedArticleKeywordSearchDialogContent.tsx @@ -0,0 +1,95 @@ +"use client"; + +import { zodResolver } from "@hookform/resolvers/zod"; +import { usePathname, useRouter } from "next/navigation"; +import { FC, useCallback } from "react"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; + +import { + DialogContent, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { + Form, + FormField, + FormItem, + FormLabel, + FormControl, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; + +import { serverRevalidatePage } from "@/actions/actServerRevalidatePage"; + +const formSchema = z.object({ + keyword: z.string().optional(), +}); + +type FeedArticleKeywordSearchDialogContentProps = { + feedId: string; + keyword?: string; + handleClose: () => void; +}; + +export const FeedArticleKeywordSearchDialogContent: FC< + FeedArticleKeywordSearchDialogContentProps +> = ({ keyword, feedId, handleClose }) => { + const pathname = usePathname(); + const router = useRouter(); + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues: { + keyword: keyword ?? "", + }, + }); + + const resetDialog = useCallback(() => { + form.reset(); + }, [form]); + + const onSubmit = async (values: z.infer) => { + let keywordPath = ""; + if (!!values.keyword && values.keyword.trim() !== "") { + keywordPath = `keyword=${values.keyword}`; + } + await serverRevalidatePage(pathname); + router.replace(`/feed/${feedId}?${keywordPath}`); + resetDialog(); + handleClose(); + }; + + return ( + + + {"Search"} + +
+
+ +
+ ( + + Keyword + + + + + + )} + /> +
+
+ +
+
+ ); +}; diff --git a/web/client-v2/src/features/feeds/components/Dialog/FeedArticleKeywordSearchDialog/index.ts b/web/client-v2/src/features/feeds/components/Dialog/FeedArticleKeywordSearchDialog/index.ts new file mode 100644 index 00000000..eada737e --- /dev/null +++ b/web/client-v2/src/features/feeds/components/Dialog/FeedArticleKeywordSearchDialog/index.ts @@ -0,0 +1 @@ +export * from "./FeedArticleKeywordSearchDialog"; diff --git a/web/client-v2/src/features/feeds/components/Dialog/index.ts b/web/client-v2/src/features/feeds/components/Dialog/index.ts index f160749f..bed385c7 100644 --- a/web/client-v2/src/features/feeds/components/Dialog/index.ts +++ b/web/client-v2/src/features/feeds/components/Dialog/index.ts @@ -1 +1,2 @@ export * from "./FeedKeywordSearchDialog"; +export * from "./FeedArticleKeywordSearchDialog"; diff --git a/web/client-v2/src/features/feeds/components/Template/FeedArticleListTemplate/FeedArticleListTemplate.tsx b/web/client-v2/src/features/feeds/components/Template/FeedArticleListTemplate/FeedArticleListTemplate.tsx index 6b9cd280..6c358250 100644 --- a/web/client-v2/src/features/feeds/components/Template/FeedArticleListTemplate/FeedArticleListTemplate.tsx +++ b/web/client-v2/src/features/feeds/components/Template/FeedArticleListTemplate/FeedArticleListTemplate.tsx @@ -7,6 +7,7 @@ import { PreloadQuery } from "@/lib/apollo/client"; import { getServerFeedArticleTemplateQuery } from "./actGetServerFeedArticleTemplateQuery"; import { FeedArticleListTemplateQuery } from "./FeedArticleListTemplateQuery"; +import { FeedArticleKeywordSearchDialog } from "../../Dialog"; import { FeedArticleList } from "../../List"; type FeedArticleListTemplateProps = { @@ -75,6 +76,10 @@ export const FeedArticleListTemplate: FC< + +
+ +
); }; From 407cfb683eb4ddf93ee65db9c422a4c4db435daa Mon Sep 17 00:00:00 2001 From: YukiOnishi <58220747+YukiOnishi1129@users.noreply.github.com> Date: Sat, 4 Jan 2025 16:41:06 +0900 Subject: [PATCH 09/19] fix search --- .../feeds/components/List/FeedArticleList/FeedArticleList.tsx | 3 +++ .../FeedArticleListTemplate/FeedArticleListTemplate.tsx | 1 + 2 files changed, 4 insertions(+) diff --git a/web/client-v2/src/features/feeds/components/List/FeedArticleList/FeedArticleList.tsx b/web/client-v2/src/features/feeds/components/List/FeedArticleList/FeedArticleList.tsx index 81733e7c..bdad5d37 100644 --- a/web/client-v2/src/features/feeds/components/List/FeedArticleList/FeedArticleList.tsx +++ b/web/client-v2/src/features/feeds/components/List/FeedArticleList/FeedArticleList.tsx @@ -26,6 +26,7 @@ export function FeedArticleList({ id, keyword }: FeedArticleListProps) { input: { first: 20, after: null, + keyword, feedIds: [id], }, favoriteArticleFoldersInput: { @@ -45,6 +46,7 @@ export function FeedArticleList({ id, keyword }: FeedArticleListProps) { input: { first: 20, after: null, + keyword, feedIds: [id], }, }, @@ -67,6 +69,7 @@ export function FeedArticleList({ id, keyword }: FeedArticleListProps) { input: { first: 20, after: endCursor, + keyword, feedIds: [id], }, }, diff --git a/web/client-v2/src/features/feeds/components/Template/FeedArticleListTemplate/FeedArticleListTemplate.tsx b/web/client-v2/src/features/feeds/components/Template/FeedArticleListTemplate/FeedArticleListTemplate.tsx index 6c358250..99ebb746 100644 --- a/web/client-v2/src/features/feeds/components/Template/FeedArticleListTemplate/FeedArticleListTemplate.tsx +++ b/web/client-v2/src/features/feeds/components/Template/FeedArticleListTemplate/FeedArticleListTemplate.tsx @@ -64,6 +64,7 @@ export const FeedArticleListTemplate: FC< input: { first: 20, after: null, + keyword, feedIds: [id], }, favoriteArticleFoldersInput: { From ae5fa332b1642349ea15b1bcc118a8efd47d03a0 Mon Sep 17 00:00:00 2001 From: YukiOnishi <58220747+YukiOnishi1129@users.noreply.github.com> Date: Sat, 4 Jan 2025 16:49:54 +0900 Subject: [PATCH 10/19] fix sort --- .../adapter/persistence_adapter/favorite_article_folder.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/micro-service/favorite-service/internal/adapter/persistence_adapter/favorite_article_folder.go b/micro-service/favorite-service/internal/adapter/persistence_adapter/favorite_article_folder.go index ca0e51ec..e4d94eab 100644 --- a/micro-service/favorite-service/internal/adapter/persistence_adapter/favorite_article_folder.go +++ b/micro-service/favorite-service/internal/adapter/persistence_adapter/favorite_article_folder.go @@ -34,7 +34,7 @@ func (fafa *favoriteArticleFolderPersistenceAdapter) GetFavoriteArticleFolders(c q := []qm.QueryMod{ qm.Where("favorite_article_folders.user_id = ?", req.GetUserId()), qm.GroupBy("favorite_article_folders.id"), - qm.OrderBy("favorite_article_folders.created_at ASC"), + qm.OrderBy("favorite_article_folders.title ASC"), } if !req.GetIsAllFetch().GetValue() { @@ -46,7 +46,7 @@ func (fafa *favoriteArticleFolderPersistenceAdapter) GetFavoriteArticleFolders(c } if req.GetCursor() != nil { - q = append(q, qm.Where("favorite_article_folders.created_at > (SELECT created_at FROM favorite_article_folders WHERE id = ?)", req.GetCursor().GetValue())) + q = append(q, qm.Where("favorite_article_folders.title > (SELECT title FROM favorite_article_folders WHERE id = ?)", req.GetCursor().GetValue())) } if req.GetKeyword().GetValue() != "" { From 2adb7d73bc0856ca52ffa22899f37bd82eaa6fe7 Mon Sep 17 00:00:00 2001 From: YukiOnishi <58220747+YukiOnishi1129@users.noreply.github.com> Date: Sat, 4 Jan 2025 16:52:26 +0900 Subject: [PATCH 11/19] fix sort --- .../internal/adapter/persistence_adapter/my_feed_folder.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/micro-service/my-feed-service/internal/adapter/persistence_adapter/my_feed_folder.go b/micro-service/my-feed-service/internal/adapter/persistence_adapter/my_feed_folder.go index af21beed..6d82f0cc 100644 --- a/micro-service/my-feed-service/internal/adapter/persistence_adapter/my_feed_folder.go +++ b/micro-service/my-feed-service/internal/adapter/persistence_adapter/my_feed_folder.go @@ -33,7 +33,7 @@ func (m *myFeedFolderPersistenceAdapter) GetMyFeedFolders(ctx context.Context, r q := []qm.QueryMod{ qm.Where("my_feed_folders.user_id = ?", req.GetUserId()), qm.Load(qm.Rels(entity.MyFeedFolderRels.MyFeeds)), - qm.OrderBy("my_feed_folders.created_at ASC"), + qm.OrderBy("my_feed_folders.title ASC"), } if !req.GetIsAllFetch().GetValue() { @@ -41,7 +41,7 @@ func (m *myFeedFolderPersistenceAdapter) GetMyFeedFolders(ctx context.Context, r } if req.GetCursor() != "" { - q = append(q, qm.Where("my_feed_folders.created_at > (SELECT created_at FROM my_feed_folders WHERE id = ?)", req.GetCursor())) + q = append(q, qm.Where("my_feed_folders.title > (SELECT title FROM my_feed_folders WHERE id = ?)", req.GetCursor())) } if req.GetKeyword().GetValue() != "" { From ad0e5b6ce90d91ca438d25b3583c7cfafc2a7700 Mon Sep 17 00:00:00 2001 From: YukiOnishi <58220747+YukiOnishi1129@users.noreply.github.com> Date: Sat, 4 Jan 2025 17:07:59 +0900 Subject: [PATCH 12/19] FavoriteArticleFolderKeyWordSearchDialog --- ...voriteArticleFolderKeyWordSearchDialog.tsx | 36 +++++++ ...rticleFolderKeyWordSearchDialogContent.tsx | 94 +++++++++++++++++++ .../index.ts | 1 + .../favorites/components/Dialog/index.ts | 2 + .../FavoriteArticleFolderListTemplate.tsx | 9 +- 5 files changed, 139 insertions(+), 3 deletions(-) create mode 100644 web/client-v2/src/features/favorites/components/Dialog/FavoriteArticleFolderKeyWordSearchDialog/FavoriteArticleFolderKeyWordSearchDialog.tsx create mode 100644 web/client-v2/src/features/favorites/components/Dialog/FavoriteArticleFolderKeyWordSearchDialog/FavoriteArticleFolderKeyWordSearchDialogContent.tsx create mode 100644 web/client-v2/src/features/favorites/components/Dialog/FavoriteArticleFolderKeyWordSearchDialog/index.ts diff --git a/web/client-v2/src/features/favorites/components/Dialog/FavoriteArticleFolderKeyWordSearchDialog/FavoriteArticleFolderKeyWordSearchDialog.tsx b/web/client-v2/src/features/favorites/components/Dialog/FavoriteArticleFolderKeyWordSearchDialog/FavoriteArticleFolderKeyWordSearchDialog.tsx new file mode 100644 index 00000000..43232696 --- /dev/null +++ b/web/client-v2/src/features/favorites/components/Dialog/FavoriteArticleFolderKeyWordSearchDialog/FavoriteArticleFolderKeyWordSearchDialog.tsx @@ -0,0 +1,36 @@ +"use client"; + +import { FC, useCallback, useState } from "react"; +import { FaSearch } from "react-icons/fa"; + +import { Dialog, DialogTrigger } from "@/components/ui/dialog"; + +import { FavoriteArticleFolderKeyWordSearchDialogContent } from "./FavoriteArticleFolderKeyWordSearchDialogContent"; + +type FavoriteArticleFolderKeyWordSearchDialogProps = { + keyword?: string; +}; + +export const FavoriteArticleFolderKeyWordSearchDialog: FC< + FavoriteArticleFolderKeyWordSearchDialogProps +> = ({ keyword }) => { + const [open, setOpen] = useState(false); + + const handleClose = useCallback(() => { + setOpen(false); + }, []); + + return ( + + + + + {open && ( + + )} + + ); +}; diff --git a/web/client-v2/src/features/favorites/components/Dialog/FavoriteArticleFolderKeyWordSearchDialog/FavoriteArticleFolderKeyWordSearchDialogContent.tsx b/web/client-v2/src/features/favorites/components/Dialog/FavoriteArticleFolderKeyWordSearchDialog/FavoriteArticleFolderKeyWordSearchDialogContent.tsx new file mode 100644 index 00000000..cc587977 --- /dev/null +++ b/web/client-v2/src/features/favorites/components/Dialog/FavoriteArticleFolderKeyWordSearchDialog/FavoriteArticleFolderKeyWordSearchDialogContent.tsx @@ -0,0 +1,94 @@ +"use client"; + +import { zodResolver } from "@hookform/resolvers/zod"; +import { usePathname, useRouter } from "next/navigation"; +import { FC, useCallback } from "react"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; + +import { + DialogContent, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { + Form, + FormField, + FormItem, + FormLabel, + FormControl, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; + +import { serverRevalidatePage } from "@/actions/actServerRevalidatePage"; + +const formSchema = z.object({ + keyword: z.string().optional(), +}); + +type FavoriteArticleFolderKeyWordSearchDialogContentProps = { + keyword?: string; + onClose: () => void; +}; + +export const FavoriteArticleFolderKeyWordSearchDialogContent: FC< + FavoriteArticleFolderKeyWordSearchDialogContentProps +> = ({ keyword, onClose }) => { + const pathname = usePathname(); + const router = useRouter(); + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues: { + keyword: keyword ?? "", + }, + }); + + const resetDialog = useCallback(() => { + form.reset(); + }, [form]); + + const onSubmit = async (values: z.infer) => { + let keywordPath = ""; + if (!!values.keyword && values.keyword.trim() !== "") { + keywordPath = `keyword=${values.keyword}`; + } + await serverRevalidatePage(pathname); + router.replace(`/favorite?${keywordPath}`); + resetDialog(); + onClose(); + }; + + return ( + + + {"Search"} + +
+
+ +
+ ( + + Keyword + + + + + + )} + /> +
+
+ +
+
+ ); +}; diff --git a/web/client-v2/src/features/favorites/components/Dialog/FavoriteArticleFolderKeyWordSearchDialog/index.ts b/web/client-v2/src/features/favorites/components/Dialog/FavoriteArticleFolderKeyWordSearchDialog/index.ts new file mode 100644 index 00000000..768157a6 --- /dev/null +++ b/web/client-v2/src/features/favorites/components/Dialog/FavoriteArticleFolderKeyWordSearchDialog/index.ts @@ -0,0 +1 @@ +export * from "./FavoriteArticleFolderKeyWordSearchDialog"; diff --git a/web/client-v2/src/features/favorites/components/Dialog/index.ts b/web/client-v2/src/features/favorites/components/Dialog/index.ts index 80cc72e8..a513bd85 100644 --- a/web/client-v2/src/features/favorites/components/Dialog/index.ts +++ b/web/client-v2/src/features/favorites/components/Dialog/index.ts @@ -5,3 +5,5 @@ export * from "./RemoveFavoriteArticleAlertDialog"; export * from "./CreateFavoriteArticleDialog"; export * from "./CreateFavoriteArticleDialogFloatButton"; + +export * from "./FavoriteArticleFolderKeyWordSearchDialog"; diff --git a/web/client-v2/src/features/favorites/components/Template/FavoriteArticleFolderListTemplate/FavoriteArticleFolderListTemplate.tsx b/web/client-v2/src/features/favorites/components/Template/FavoriteArticleFolderListTemplate/FavoriteArticleFolderListTemplate.tsx index 5cd453e2..20e49851 100644 --- a/web/client-v2/src/features/favorites/components/Template/FavoriteArticleFolderListTemplate/FavoriteArticleFolderListTemplate.tsx +++ b/web/client-v2/src/features/favorites/components/Template/FavoriteArticleFolderListTemplate/FavoriteArticleFolderListTemplate.tsx @@ -6,7 +6,10 @@ import { ScreenLoader } from "@/components/layout/ScreenLoader"; import { PreloadQuery } from "@/lib/apollo/client"; import { FavoriteArticleFolderListTemplateQuery } from "./FavoriteArticleFolderListTemplateQuery"; -import { CreateFavoriteArticleFolderDialog } from "../../Dialog"; +import { + CreateFavoriteArticleFolderDialog, + FavoriteArticleFolderKeyWordSearchDialog, +} from "../../Dialog"; import { FavoriteArticleFolderList } from "../../List"; import { FavoriteArticleFolderKeywordSearchForm } from "../../Search"; @@ -50,9 +53,9 @@ export const FavoriteArticleFolderListTemplate: FC< - {/*
+
-
*/} +
); }; From 69f7aa949d301b32ccce3786a057cd41863b8b24 Mon Sep 17 00:00:00 2001 From: YukiOnishi <58220747+YukiOnishi1129@users.noreply.github.com> Date: Sat, 4 Jan 2025 17:10:06 +0900 Subject: [PATCH 13/19] SearchFavoriteArticleFolderDialog --- .../FavoriteArticleFolderKeyWordSearchDialog/index.ts | 1 - .../SearchFavoriteArticleFolderDialog.tsx} | 10 +++++----- .../SearchFavoriteArticleFolderDialogContent.tsx} | 6 +++--- .../Dialog/SearchFavoriteArticleFolderDialog/index.ts | 1 + .../src/features/favorites/components/Dialog/index.ts | 2 +- .../FavoriteArticleFolderListTemplate.tsx | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) delete mode 100644 web/client-v2/src/features/favorites/components/Dialog/FavoriteArticleFolderKeyWordSearchDialog/index.ts rename web/client-v2/src/features/favorites/components/Dialog/{FavoriteArticleFolderKeyWordSearchDialog/FavoriteArticleFolderKeyWordSearchDialog.tsx => SearchFavoriteArticleFolderDialog/SearchFavoriteArticleFolderDialog.tsx} (67%) rename web/client-v2/src/features/favorites/components/Dialog/{FavoriteArticleFolderKeyWordSearchDialog/FavoriteArticleFolderKeyWordSearchDialogContent.tsx => SearchFavoriteArticleFolderDialog/SearchFavoriteArticleFolderDialogContent.tsx} (92%) create mode 100644 web/client-v2/src/features/favorites/components/Dialog/SearchFavoriteArticleFolderDialog/index.ts diff --git a/web/client-v2/src/features/favorites/components/Dialog/FavoriteArticleFolderKeyWordSearchDialog/index.ts b/web/client-v2/src/features/favorites/components/Dialog/FavoriteArticleFolderKeyWordSearchDialog/index.ts deleted file mode 100644 index 768157a6..00000000 --- a/web/client-v2/src/features/favorites/components/Dialog/FavoriteArticleFolderKeyWordSearchDialog/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./FavoriteArticleFolderKeyWordSearchDialog"; diff --git a/web/client-v2/src/features/favorites/components/Dialog/FavoriteArticleFolderKeyWordSearchDialog/FavoriteArticleFolderKeyWordSearchDialog.tsx b/web/client-v2/src/features/favorites/components/Dialog/SearchFavoriteArticleFolderDialog/SearchFavoriteArticleFolderDialog.tsx similarity index 67% rename from web/client-v2/src/features/favorites/components/Dialog/FavoriteArticleFolderKeyWordSearchDialog/FavoriteArticleFolderKeyWordSearchDialog.tsx rename to web/client-v2/src/features/favorites/components/Dialog/SearchFavoriteArticleFolderDialog/SearchFavoriteArticleFolderDialog.tsx index 43232696..c3cf61ab 100644 --- a/web/client-v2/src/features/favorites/components/Dialog/FavoriteArticleFolderKeyWordSearchDialog/FavoriteArticleFolderKeyWordSearchDialog.tsx +++ b/web/client-v2/src/features/favorites/components/Dialog/SearchFavoriteArticleFolderDialog/SearchFavoriteArticleFolderDialog.tsx @@ -5,14 +5,14 @@ import { FaSearch } from "react-icons/fa"; import { Dialog, DialogTrigger } from "@/components/ui/dialog"; -import { FavoriteArticleFolderKeyWordSearchDialogContent } from "./FavoriteArticleFolderKeyWordSearchDialogContent"; +import { SearchFavoriteArticleFolderDialogContent } from "./SearchFavoriteArticleFolderDialogContent"; -type FavoriteArticleFolderKeyWordSearchDialogProps = { +type SearchFavoriteArticleFolderDialogProps = { keyword?: string; }; -export const FavoriteArticleFolderKeyWordSearchDialog: FC< - FavoriteArticleFolderKeyWordSearchDialogProps +export const SearchFavoriteArticleFolderDialog: FC< + SearchFavoriteArticleFolderDialogProps > = ({ keyword }) => { const [open, setOpen] = useState(false); @@ -26,7 +26,7 @@ export const FavoriteArticleFolderKeyWordSearchDialog: FC< {open && ( - diff --git a/web/client-v2/src/features/favorites/components/Dialog/FavoriteArticleFolderKeyWordSearchDialog/FavoriteArticleFolderKeyWordSearchDialogContent.tsx b/web/client-v2/src/features/favorites/components/Dialog/SearchFavoriteArticleFolderDialog/SearchFavoriteArticleFolderDialogContent.tsx similarity index 92% rename from web/client-v2/src/features/favorites/components/Dialog/FavoriteArticleFolderKeyWordSearchDialog/FavoriteArticleFolderKeyWordSearchDialogContent.tsx rename to web/client-v2/src/features/favorites/components/Dialog/SearchFavoriteArticleFolderDialog/SearchFavoriteArticleFolderDialogContent.tsx index cc587977..8727ccf2 100644 --- a/web/client-v2/src/features/favorites/components/Dialog/FavoriteArticleFolderKeyWordSearchDialog/FavoriteArticleFolderKeyWordSearchDialogContent.tsx +++ b/web/client-v2/src/features/favorites/components/Dialog/SearchFavoriteArticleFolderDialog/SearchFavoriteArticleFolderDialogContent.tsx @@ -27,13 +27,13 @@ const formSchema = z.object({ keyword: z.string().optional(), }); -type FavoriteArticleFolderKeyWordSearchDialogContentProps = { +type SearchFavoriteArticleFolderDialogContentProps = { keyword?: string; onClose: () => void; }; -export const FavoriteArticleFolderKeyWordSearchDialogContent: FC< - FavoriteArticleFolderKeyWordSearchDialogContentProps +export const SearchFavoriteArticleFolderDialogContent: FC< + SearchFavoriteArticleFolderDialogContentProps > = ({ keyword, onClose }) => { const pathname = usePathname(); const router = useRouter(); diff --git a/web/client-v2/src/features/favorites/components/Dialog/SearchFavoriteArticleFolderDialog/index.ts b/web/client-v2/src/features/favorites/components/Dialog/SearchFavoriteArticleFolderDialog/index.ts new file mode 100644 index 00000000..940bd829 --- /dev/null +++ b/web/client-v2/src/features/favorites/components/Dialog/SearchFavoriteArticleFolderDialog/index.ts @@ -0,0 +1 @@ +export * from "./SearchFavoriteArticleFolderDialog"; diff --git a/web/client-v2/src/features/favorites/components/Dialog/index.ts b/web/client-v2/src/features/favorites/components/Dialog/index.ts index a513bd85..7763ef31 100644 --- a/web/client-v2/src/features/favorites/components/Dialog/index.ts +++ b/web/client-v2/src/features/favorites/components/Dialog/index.ts @@ -6,4 +6,4 @@ export * from "./RemoveFavoriteArticleAlertDialog"; export * from "./CreateFavoriteArticleDialog"; export * from "./CreateFavoriteArticleDialogFloatButton"; -export * from "./FavoriteArticleFolderKeyWordSearchDialog"; +export * from "./SearchFavoriteArticleFolderDialog"; diff --git a/web/client-v2/src/features/favorites/components/Template/FavoriteArticleFolderListTemplate/FavoriteArticleFolderListTemplate.tsx b/web/client-v2/src/features/favorites/components/Template/FavoriteArticleFolderListTemplate/FavoriteArticleFolderListTemplate.tsx index 20e49851..aac30ae2 100644 --- a/web/client-v2/src/features/favorites/components/Template/FavoriteArticleFolderListTemplate/FavoriteArticleFolderListTemplate.tsx +++ b/web/client-v2/src/features/favorites/components/Template/FavoriteArticleFolderListTemplate/FavoriteArticleFolderListTemplate.tsx @@ -8,7 +8,7 @@ import { PreloadQuery } from "@/lib/apollo/client"; import { FavoriteArticleFolderListTemplateQuery } from "./FavoriteArticleFolderListTemplateQuery"; import { CreateFavoriteArticleFolderDialog, - FavoriteArticleFolderKeyWordSearchDialog, + SearchFavoriteArticleFolderDialog, } from "../../Dialog"; import { FavoriteArticleFolderList } from "../../List"; import { FavoriteArticleFolderKeywordSearchForm } from "../../Search"; @@ -54,7 +54,7 @@ export const FavoriteArticleFolderListTemplate: FC<
- +
); From 7fb40ae42c04d57a6f3b061ae2536b7ba2a5dc99 Mon Sep 17 00:00:00 2001 From: YukiOnishi <58220747+YukiOnishi1129@users.noreply.github.com> Date: Sat, 4 Jan 2025 17:22:01 +0900 Subject: [PATCH 14/19] favorite search --- .../SearchFavoriteArticleListDialog.tsx | 38 ++++++ ...SearchFavoriteArticleListDialogContent.tsx | 114 ++++++++++++++++++ .../SearchFavoriteArticleListDialog/index.ts | 1 + .../favorites/components/Dialog/index.ts | 1 + .../AllFolderFavoriteArticleListTemplate.tsx | 10 +- .../FavoriteArticleListByFolderIdTemplate.tsx | 11 +- 6 files changed, 165 insertions(+), 10 deletions(-) create mode 100644 web/client-v2/src/features/favorites/components/Dialog/SearchFavoriteArticleListDialog/SearchFavoriteArticleListDialog.tsx create mode 100644 web/client-v2/src/features/favorites/components/Dialog/SearchFavoriteArticleListDialog/SearchFavoriteArticleListDialogContent.tsx create mode 100644 web/client-v2/src/features/favorites/components/Dialog/SearchFavoriteArticleListDialog/index.ts diff --git a/web/client-v2/src/features/favorites/components/Dialog/SearchFavoriteArticleListDialog/SearchFavoriteArticleListDialog.tsx b/web/client-v2/src/features/favorites/components/Dialog/SearchFavoriteArticleListDialog/SearchFavoriteArticleListDialog.tsx new file mode 100644 index 00000000..659a423a --- /dev/null +++ b/web/client-v2/src/features/favorites/components/Dialog/SearchFavoriteArticleListDialog/SearchFavoriteArticleListDialog.tsx @@ -0,0 +1,38 @@ +"use client"; + +import { FC, useCallback, useState } from "react"; +import { FaSearch } from "react-icons/fa"; + +import { Dialog, DialogTrigger } from "@/components/ui/dialog"; + +import { SearchFavoriteArticleListDialogContent } from "./SearchFavoriteArticleListDialogContent"; + +type SearchFavoriteArticleListDialogProps = { + favoriteArticleFolderId?: string; + keyword?: string; +}; + +export const SearchFavoriteArticleListDialog: FC< + SearchFavoriteArticleListDialogProps +> = ({ favoriteArticleFolderId, keyword }) => { + const [open, setOpen] = useState(false); + + const handleClose = useCallback(() => { + setOpen(false); + }, []); + + return ( + + + + + {open && ( + + )} + + ); +}; diff --git a/web/client-v2/src/features/favorites/components/Dialog/SearchFavoriteArticleListDialog/SearchFavoriteArticleListDialogContent.tsx b/web/client-v2/src/features/favorites/components/Dialog/SearchFavoriteArticleListDialog/SearchFavoriteArticleListDialogContent.tsx new file mode 100644 index 00000000..b6169b21 --- /dev/null +++ b/web/client-v2/src/features/favorites/components/Dialog/SearchFavoriteArticleListDialog/SearchFavoriteArticleListDialogContent.tsx @@ -0,0 +1,114 @@ +"use client"; + +import { zodResolver } from "@hookform/resolvers/zod"; +import { usePathname, useRouter } from "next/navigation"; +import { FC, useCallback } from "react"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; + +import { Button } from "@/components/ui/button"; +import { + DialogContent, + DialogHeader, + DialogTitle, + DialogClose, +} from "@/components/ui/dialog"; +import { + Form, + FormField, + FormItem, + FormLabel, + FormControl, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; + +import { serverRevalidatePage } from "@/actions/actServerRevalidatePage"; + +const formSchema = z.object({ + keyword: z.string().optional(), +}); + +type SearchFavoriteArticleListDialogContentProps = { + favoriteArticleFolderId?: string; + keyword?: string; + onClose: () => void; +}; + +export const SearchFavoriteArticleListDialogContent: FC< + SearchFavoriteArticleListDialogContentProps +> = ({ favoriteArticleFolderId, keyword, onClose }) => { + const pathname = usePathname(); + const router = useRouter(); + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues: { + keyword: keyword ?? "", + }, + }); + + const resetDialog = useCallback(() => { + form.reset(); + }, [form]); + + const onSubmit = async (values: z.infer) => { + let keywordPath = ""; + if (!!values.keyword && values.keyword.trim() !== "") { + keywordPath = `keyword=${values.keyword}`; + } + await serverRevalidatePage(pathname); + if (!favoriteArticleFolderId) { + router.replace(`/favorite/article?${keywordPath}`); + resetDialog(); + onClose(); + return; + } + router.replace( + `/favorite/article/${favoriteArticleFolderId}?${keywordPath}` + ); + resetDialog(); + onClose(); + }; + + return ( + + + {"Search"} + +
+
+ +
+ ( + + Keyword + + + + + + )} + /> +
+ +
+ + + + +
+
+ +
+
+ ); +}; diff --git a/web/client-v2/src/features/favorites/components/Dialog/SearchFavoriteArticleListDialog/index.ts b/web/client-v2/src/features/favorites/components/Dialog/SearchFavoriteArticleListDialog/index.ts new file mode 100644 index 00000000..feed3ad5 --- /dev/null +++ b/web/client-v2/src/features/favorites/components/Dialog/SearchFavoriteArticleListDialog/index.ts @@ -0,0 +1 @@ +export * from "./SearchFavoriteArticleListDialog"; diff --git a/web/client-v2/src/features/favorites/components/Dialog/index.ts b/web/client-v2/src/features/favorites/components/Dialog/index.ts index 7763ef31..4f0fb69e 100644 --- a/web/client-v2/src/features/favorites/components/Dialog/index.ts +++ b/web/client-v2/src/features/favorites/components/Dialog/index.ts @@ -7,3 +7,4 @@ export * from "./CreateFavoriteArticleDialog"; export * from "./CreateFavoriteArticleDialogFloatButton"; export * from "./SearchFavoriteArticleFolderDialog"; +export * from "./SearchFavoriteArticleListDialog"; diff --git a/web/client-v2/src/features/favorites/components/Template/AllFolderFavoriteArticleListTemplate/AllFolderFavoriteArticleListTemplate.tsx b/web/client-v2/src/features/favorites/components/Template/AllFolderFavoriteArticleListTemplate/AllFolderFavoriteArticleListTemplate.tsx index 1e5a4aab..a63a5afd 100644 --- a/web/client-v2/src/features/favorites/components/Template/AllFolderFavoriteArticleListTemplate/AllFolderFavoriteArticleListTemplate.tsx +++ b/web/client-v2/src/features/favorites/components/Template/AllFolderFavoriteArticleListTemplate/AllFolderFavoriteArticleListTemplate.tsx @@ -12,6 +12,7 @@ import { } from "@/graphql/type"; import { AllFolderFavoriteArticleListTemplateQuery } from "./AllFolderFavoriteArticleListTemplateQuery"; +import { SearchFavoriteArticleListDialog } from "../../Dialog"; import { AllFolderFavoriteArticleList } from "../../List"; import { FavoriteArticleKeywordSearchForm } from "../../Search"; @@ -78,12 +79,9 @@ export const AllFolderFavoriteArticleListTemplate: FC< - {/*
- -
*/} +
+ +
); }; diff --git a/web/client-v2/src/features/favorites/components/Template/FavoriteArticleListByFolderIdTemplate/FavoriteArticleListByFolderIdTemplate.tsx b/web/client-v2/src/features/favorites/components/Template/FavoriteArticleListByFolderIdTemplate/FavoriteArticleListByFolderIdTemplate.tsx index 8a6ed332..94ba6bfc 100644 --- a/web/client-v2/src/features/favorites/components/Template/FavoriteArticleListByFolderIdTemplate/FavoriteArticleListByFolderIdTemplate.tsx +++ b/web/client-v2/src/features/favorites/components/Template/FavoriteArticleListByFolderIdTemplate/FavoriteArticleListByFolderIdTemplate.tsx @@ -13,7 +13,10 @@ import { import { getServerFavoriteArticleListByFolderIdTemplateQuery } from "./actGetServerFavoriteArticleListByFolderIdTemplateQuery"; import { FavoriteArticleListByFolderIdTemplateQuery } from "./FavoriteArticleListByFolderIdTemplateQuery"; -import { CreateFavoriteArticleDialog } from "../../Dialog"; +import { + CreateFavoriteArticleDialog, + SearchFavoriteArticleListDialog, +} from "../../Dialog"; import { FavoriteArticleList } from "../../List/FavoriteArticleList/FavoriteArticleList"; import { FavoriteArticleKeywordSearchForm } from "../../Search"; @@ -96,12 +99,12 @@ export const FavoriteArticleListByFolderIdTemplate: FC< - {/*
- + -
*/} +
); }; From 706a3ead15f618a6bc078122b2a549880ba0ea3c Mon Sep 17 00:00:00 2001 From: YukiOnishi <58220747+YukiOnishi1129@users.noreply.github.com> Date: Sat, 4 Jan 2025 17:35:39 +0900 Subject: [PATCH 15/19] search --- .../FeedArticleKeywordSearchForm.tsx | 70 +++++ .../FeedArticleKeywordSearchForm/index.ts | 1 + .../features/feeds/components/Search/index.ts | 1 + .../FeedArticleHeader/FeedArticleHeader.tsx | 289 ++++++++++++++++++ .../FeedArticleHeaderQuery.ts | 13 + .../FeedArticleHeader/index.ts | 1 + .../FeedArticleListTemplate.tsx | 10 +- 7 files changed, 377 insertions(+), 8 deletions(-) create mode 100644 web/client-v2/src/features/feeds/components/Search/FeedArticleKeywordSearchForm/FeedArticleKeywordSearchForm.tsx create mode 100644 web/client-v2/src/features/feeds/components/Search/FeedArticleKeywordSearchForm/index.ts create mode 100644 web/client-v2/src/features/feeds/components/Template/FeedArticleListTemplate/FeedArticleHeader/FeedArticleHeader.tsx create mode 100644 web/client-v2/src/features/feeds/components/Template/FeedArticleListTemplate/FeedArticleHeader/FeedArticleHeaderQuery.ts create mode 100644 web/client-v2/src/features/feeds/components/Template/FeedArticleListTemplate/FeedArticleHeader/index.ts diff --git a/web/client-v2/src/features/feeds/components/Search/FeedArticleKeywordSearchForm/FeedArticleKeywordSearchForm.tsx b/web/client-v2/src/features/feeds/components/Search/FeedArticleKeywordSearchForm/FeedArticleKeywordSearchForm.tsx new file mode 100644 index 00000000..9c76da10 --- /dev/null +++ b/web/client-v2/src/features/feeds/components/Search/FeedArticleKeywordSearchForm/FeedArticleKeywordSearchForm.tsx @@ -0,0 +1,70 @@ +"use client"; + +import { zodResolver } from "@hookform/resolvers/zod"; +import { useRouter, usePathname } from "next/navigation"; +import { FC } from "react"; +import { useForm } from "react-hook-form"; +import { CiSearch } from "react-icons/ci"; +import { z } from "zod"; + +import { Form, FormField, FormItem, FormControl } from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; + +import { serverRevalidatePage } from "@/actions/actServerRevalidatePage"; + +const formSchema = z.object({ + keyword: z.string().optional(), +}); + +type FeedArticleKeywordSearchFormProps = { + keyword?: string; + feedId: string; +}; + +export const FeedArticleKeywordSearchForm: FC< + FeedArticleKeywordSearchFormProps +> = ({ feedId, keyword }) => { + const router = useRouter(); + const pathname = usePathname(); + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues: { + keyword: keyword ?? "", + }, + }); + + const onSubmit = async (values: z.infer) => { + let keywordPath = ""; + if (!!values.keyword && values.keyword.trim() !== "") { + keywordPath = `keyword=${values.keyword}`; + } + await serverRevalidatePage(pathname); + router.replace(`/feed/${feedId}?${keywordPath}`); + }; + + return ( +
+ + ( + +
+ +
+ + + + +
+ )} + /> + + + ); +}; diff --git a/web/client-v2/src/features/feeds/components/Search/FeedArticleKeywordSearchForm/index.ts b/web/client-v2/src/features/feeds/components/Search/FeedArticleKeywordSearchForm/index.ts new file mode 100644 index 00000000..8c7cc683 --- /dev/null +++ b/web/client-v2/src/features/feeds/components/Search/FeedArticleKeywordSearchForm/index.ts @@ -0,0 +1 @@ +export * from "./FeedArticleKeywordSearchForm"; diff --git a/web/client-v2/src/features/feeds/components/Search/index.ts b/web/client-v2/src/features/feeds/components/Search/index.ts index b4136270..b6957db7 100644 --- a/web/client-v2/src/features/feeds/components/Search/index.ts +++ b/web/client-v2/src/features/feeds/components/Search/index.ts @@ -1 +1,2 @@ export * from "./FeedKeywordSearchForm"; +export * from "./FeedArticleKeywordSearchForm"; diff --git a/web/client-v2/src/features/feeds/components/Template/FeedArticleListTemplate/FeedArticleHeader/FeedArticleHeader.tsx b/web/client-v2/src/features/feeds/components/Template/FeedArticleListTemplate/FeedArticleHeader/FeedArticleHeader.tsx new file mode 100644 index 00000000..540a0afb --- /dev/null +++ b/web/client-v2/src/features/feeds/components/Template/FeedArticleListTemplate/FeedArticleHeader/FeedArticleHeader.tsx @@ -0,0 +1,289 @@ +"use client"; +import { useQuery } from "@apollo/client"; +import { User } from "@supabase/supabase-js"; +import { FC } from "react"; + +import { useCheckImageExist } from "@/hooks/useImage"; +import { useStatusToast } from "@/hooks/useStatusToast"; + +import { FeedArticleHeaderQuery } from "./FeedArticleHeaderQuery"; +import { FeedArticleKeywordSearchForm } from "../../../Search"; + +type FeedArticleHeaderProps = { + feedId: string; + user?: User; + keyword?: string; +}; + +export const FeedArticleHeader: FC = ({ + feedId, + user, + keyword, +}) => { + const { successToast, failToast } = useStatusToast(); + + const { data, loading, error } = useQuery(FeedArticleHeaderQuery, { + variables: { + input: { + id: feedId, + }, + }, + fetchPolicy: "cache-and-network", + }); + + const faviconImage = useCheckImageExist(data?.feed.platform.faviconUrl || ""); + + if (loading) return
Loading...
; + if (error) return
Error...
; + + // const addStateFeedInMyFeedFolder = useCallback( + // ( + // targetMyFeedFolder: MyFeedFolderType, + // myFeedId: string + // ): MyFeedFolderType => { + // const newMyFeedFolder: MyFeedFolderType = { + // ...targetMyFeedFolder, + // feeds: [ + // ...targetMyFeedFolder.feeds, + // { + // id: showFeed.id, + // platformId: showFeed.platform.id, + // categoryId: showFeed.category.id, + // name: showFeed.name, + // description: showFeed.description, + // thumbnailUrl: showFeed.thumbnailUrl, + // siteUrl: showFeed.siteUrl, + // rssUrl: showFeed.rssUrl, + // apiQueryParam: showFeed.apiQueryParam, + // trendPlatformType: showFeed.trendPlatformType, + // createdAt: showFeed.createdAt, + // updatedAt: showFeed.updatedAt, + // category: { + // id: showFeed.category.id, + // type: showFeed.category.type, + // name: showFeed.category.name, + // createdAt: showFeed.category.createdAt, + // updatedAt: showFeed.category.updatedAt, + // }, + // platform: { + // id: showFeed.platform.id, + // name: showFeed.platform.name, + // siteUrl: showFeed.platform.siteUrl, + // faviconUrl: showFeed.platform.faviconUrl, + // platformSiteType: showFeed.platform.platformSiteType, + // isEng: showFeed.platform.isEng, + // createdAt: showFeed.platform.createdAt, + // updatedAt: showFeed.platform.updatedAt, + // }, + // myFeedId: myFeedId, + // }, + // ], + // }; + // return newMyFeedFolder; + // }, + // [showFeed] + // ); + + // const handleCreateMyFeed = useCallback( + // async (myFeedFolderId: string, createdMyFeedFolder?: MyFeedFolderType) => { + // // login check + // const user = await getUser(); + // if (!user) { + // failToast({ + // description: "Please sign in to follow the feed", + // }); + // await logoutToLoginPage(); + // return; + // } + + // // check count myFeed by myFeedFolderId and feedId + // const res = await fetchMyFeedCountByMyFeedFolderIdAndFeedIdAPI({ + // feedId: showFeed.id, + // myFeedFolderId, + // }); + // if (res.data?.count && res.data.count > 0) { + // failToast({ + // description: "You are already following the feed", + // }); + // return; + // } + + // // create myFeed + // const createdData = await createMyFeed({ + // userId: user.id, + // myFeedFolderId, + // feedId: showFeed.id, + // }); + // if (!createdData) { + // failToast({ + // description: "Failed to follow the feed", + // }); + // return; + // } + // successToast({ + // description: "Successfully followed the feed", + // }); + + // // state update + // if (!isFollowing) setIsFollowing(true); + // // add feed to myFeedFolder + // if (createdMyFeedFolder) { + // setShowMyFeedFolders((prev) => [ + // ...prev, + // addStateFeedInMyFeedFolder(createdMyFeedFolder, createdData.id), + // ]); + // return createdData.id; + // } + + // const targetMyFeedFolder = showMyFeedFolders.find( + // (myFeedFolder) => myFeedFolder.id === myFeedFolderId + // ); + // if (targetMyFeedFolder) { + // setShowMyFeedFolders((prev) => [ + // ...prev.filter((myFeedFolder) => myFeedFolder.id !== myFeedFolderId), + // addStateFeedInMyFeedFolder(targetMyFeedFolder, createdData.id), + // ]); + // } + + // setShowFeed({ + // ...showFeed, + // myFeeds: [ + // ...(showFeed.myFeeds || []), + // { + // id: createdData.id, + // myFeedFolderId, + // userId: user.id, + // feedId: showFeed.id, + // createdAt: createdData.createdAt, + // updatedAt: createdData.updatedAt, + // }, + // ], + // }); + + // return createdData.id; + // }, + // [ + // failToast, + // showFeed, + // isFollowing, + // successToast, + // showMyFeedFolders, + // addStateFeedInMyFeedFolder, + // ] + // ); + + // const handleCreatedMyFeedFolder = useCallback( + // async (myFeedFolderId: string) => { + // const res = await fetchMyFeedFolderByIdAPI(myFeedFolderId); + // const newMyFeedFolders = res.data.myFeedFolders; + // const id = await handleCreateMyFeed(myFeedFolderId, newMyFeedFolders); + + // if (id) { + // successToast({ + // description: "Successfully followed the feed", + // }); + // } + // }, + // [handleCreateMyFeed, successToast] + // ); + + // const handleRemoveMyFeed = useCallback( + // async (myFeedId: string, myFeedFolderId: string) => { + // const user = await getUser(); + // if (!user) { + // failToast({ + // description: "Please sign in to follow the feed", + // }); + // await logoutToLoginPage(); + // return; + // } + + // // check count myFeed by myFeedId + // const targetId = await fetchMyFeedById({ + // id: myFeedId, + // }); + // if (!targetId) { + // failToast({ + // description: "Failed to unfollow the feed", + // }); + // return; + // } + + // const id = await deleteMyFeed({ + // id: myFeedId, + // userId: user.id, + // }); + + // if (!id) { + // failToast({ + // description: "Failed to unfollow the feed", + // }); + // return; + // } + // successToast({ + // description: "Successfully unfollowed the feed", + // }); + + // // state update + // // remove feed from myFeedFolder + // const targetMyFeedFolder = showMyFeedFolders.find( + // (myFeedFolder) => myFeedFolder.id === myFeedFolderId + // ); + // if (targetMyFeedFolder) { + // const newMyFeedFolder: MyFeedFolderType = { + // ...targetMyFeedFolder, + // feeds: targetMyFeedFolder.feeds.filter( + // (myFeed) => myFeed.id !== showFeed.id + // ), + // }; + // setShowMyFeedFolders((prev) => [ + // ...prev.filter((myFeedFolder) => myFeedFolder.id !== myFeedFolderId), + // newMyFeedFolder, + // ]); + // } + + // if (showFeed?.myFeeds) { + // const newFeed: FeedType = { + // ...showFeed, + // myFeeds: showFeed.myFeeds.filter((myFeed) => myFeed.id !== myFeedId), + // }; + // setShowFeed(newFeed); + // if (!newFeed?.myFeeds || newFeed.myFeeds.length === 0) { + // setIsFollowing(false); + // } + // } + + // return id; + // }, + // [successToast, failToast, showMyFeedFolders, showFeed] + // ); + + return ( +
+
+ +
+
+ {/* eslint-disable-next-line @next/next/no-img-element */} + +
+

+ {data?.feed.name} +

+
+
+ {/* {user && ( +
+ +
+ )} */} +
+ ); +}; diff --git a/web/client-v2/src/features/feeds/components/Template/FeedArticleListTemplate/FeedArticleHeader/FeedArticleHeaderQuery.ts b/web/client-v2/src/features/feeds/components/Template/FeedArticleListTemplate/FeedArticleHeader/FeedArticleHeaderQuery.ts new file mode 100644 index 00000000..c62600c9 --- /dev/null +++ b/web/client-v2/src/features/feeds/components/Template/FeedArticleListTemplate/FeedArticleHeader/FeedArticleHeaderQuery.ts @@ -0,0 +1,13 @@ +import { graphql } from "gql.tada"; + +export const FeedArticleHeaderQuery = graphql(` + query FeedArticleHeaderQuery($input: FeedInput!) { + feed(feedInput: $input) { + id + name + platform { + faviconUrl + } + } + } +`); diff --git a/web/client-v2/src/features/feeds/components/Template/FeedArticleListTemplate/FeedArticleHeader/index.ts b/web/client-v2/src/features/feeds/components/Template/FeedArticleListTemplate/FeedArticleHeader/index.ts new file mode 100644 index 00000000..45e407ed --- /dev/null +++ b/web/client-v2/src/features/feeds/components/Template/FeedArticleListTemplate/FeedArticleHeader/index.ts @@ -0,0 +1 @@ +export * from "./FeedArticleHeader"; diff --git a/web/client-v2/src/features/feeds/components/Template/FeedArticleListTemplate/FeedArticleListTemplate.tsx b/web/client-v2/src/features/feeds/components/Template/FeedArticleListTemplate/FeedArticleListTemplate.tsx index 99ebb746..a2ddb1e9 100644 --- a/web/client-v2/src/features/feeds/components/Template/FeedArticleListTemplate/FeedArticleListTemplate.tsx +++ b/web/client-v2/src/features/feeds/components/Template/FeedArticleListTemplate/FeedArticleListTemplate.tsx @@ -6,6 +6,7 @@ import { BreadCrumbType, PageBreadcrumb } from "@/components/ui/breadcrumb"; import { PreloadQuery } from "@/lib/apollo/client"; import { getServerFeedArticleTemplateQuery } from "./actGetServerFeedArticleTemplateQuery"; +import { FeedArticleHeader } from "./FeedArticleHeader"; import { FeedArticleListTemplateQuery } from "./FeedArticleListTemplateQuery"; import { FeedArticleKeywordSearchDialog } from "../../Dialog"; import { FeedArticleList } from "../../List"; @@ -45,14 +46,7 @@ export const FeedArticleListTemplate: FC<
- {/* {resFeed.data.feed && ( - - )} */} +
From 8b8b916d728cafa6996acd41e0852d1f4ee93b81 Mon Sep 17 00:00:00 2001 From: YukiOnishi <58220747+YukiOnishi1129@users.noreply.github.com> Date: Sat, 4 Jan 2025 17:42:05 +0900 Subject: [PATCH 16/19] SearchMyFeedFolderArticleDialog --- .../SearchMyFeedFolderArticleDialog.tsx | 38 ++++++++ ...SearchMyFeedFolderArticleDialogContent.tsx | 95 +++++++++++++++++++ .../SearchMyFeedFolderArticleDialog/index.ts | 1 + .../myFeeds/components/Dialog/index.ts | 2 + .../MyFeedFolderArticleListTemplate.tsx | 7 +- 5 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderArticleDialog/SearchMyFeedFolderArticleDialog.tsx create mode 100644 web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderArticleDialog/SearchMyFeedFolderArticleDialogContent.tsx create mode 100644 web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderArticleDialog/index.ts diff --git a/web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderArticleDialog/SearchMyFeedFolderArticleDialog.tsx b/web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderArticleDialog/SearchMyFeedFolderArticleDialog.tsx new file mode 100644 index 00000000..9b387c54 --- /dev/null +++ b/web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderArticleDialog/SearchMyFeedFolderArticleDialog.tsx @@ -0,0 +1,38 @@ +"use client"; + +import { FC, useCallback, useState } from "react"; +import { FaSearch } from "react-icons/fa"; + +import { Dialog, DialogTrigger } from "@/components/ui/dialog"; + +import { SearchMyFeedFolderArticleDialogContent } from "./SearchMyFeedFolderArticleDialogContent"; + +type SearchMyFeedFolderArticleDialogProps = { + myFeedFolderId: string; + keyword?: string; +}; + +export const SearchMyFeedFolderArticleDialog: FC< + SearchMyFeedFolderArticleDialogProps +> = ({ myFeedFolderId, keyword }) => { + const [open, setOpen] = useState(false); + + const handleClose = useCallback(() => { + setOpen(false); + }, []); + + return ( + + + + + {open && ( + + )} + + ); +}; diff --git a/web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderArticleDialog/SearchMyFeedFolderArticleDialogContent.tsx b/web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderArticleDialog/SearchMyFeedFolderArticleDialogContent.tsx new file mode 100644 index 00000000..19eef14f --- /dev/null +++ b/web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderArticleDialog/SearchMyFeedFolderArticleDialogContent.tsx @@ -0,0 +1,95 @@ +"use client"; + +import { zodResolver } from "@hookform/resolvers/zod"; +import { usePathname, useRouter } from "next/navigation"; +import { FC, useCallback } from "react"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; + +import { + DialogContent, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { + Form, + FormField, + FormItem, + FormLabel, + FormControl, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; + +import { serverRevalidatePage } from "@/actions/actServerRevalidatePage"; + +const formSchema = z.object({ + keyword: z.string().optional(), +}); + +type SearchMyFeedFolderArticleDialogContentProps = { + myFeedFolderId: string; + keyword?: string; + handleClose: () => void; +}; + +export const SearchMyFeedFolderArticleDialogContent: FC< + SearchMyFeedFolderArticleDialogContentProps +> = ({ myFeedFolderId, keyword, handleClose }) => { + const pathname = usePathname(); + const router = useRouter(); + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues: { + keyword: keyword ?? "", + }, + }); + + const resetDialog = useCallback(() => { + form.reset(); + }, [form]); + + const onSubmit = async (values: z.infer) => { + let keywordPath = ""; + if (!!values.keyword && values.keyword.trim() !== "") { + keywordPath = `keyword=${values.keyword}`; + } + await serverRevalidatePage(pathname); + router.replace(`/my-feed/article/${myFeedFolderId}?${keywordPath}`); + resetDialog(); + handleClose(); + }; + + return ( + + + {"Search"} + +
+
+ +
+ ( + + Keyword + + + + + + )} + /> +
+
+ +
+
+ ); +}; diff --git a/web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderArticleDialog/index.ts b/web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderArticleDialog/index.ts new file mode 100644 index 00000000..68b6376d --- /dev/null +++ b/web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderArticleDialog/index.ts @@ -0,0 +1 @@ +export * from "./SearchMyFeedFolderArticleDialog"; diff --git a/web/client-v2/src/features/myFeeds/components/Dialog/index.ts b/web/client-v2/src/features/myFeeds/components/Dialog/index.ts index 9c4d198e..18ef0b1e 100644 --- a/web/client-v2/src/features/myFeeds/components/Dialog/index.ts +++ b/web/client-v2/src/features/myFeeds/components/Dialog/index.ts @@ -1,3 +1,5 @@ export * from "./CreateMyFeedFolderDialog"; export * from "./UpdateMyFeedFolderDialog"; export * from "./ShowMyFeedListDialog"; + +export * from "./SearchMyFeedFolderArticleDialog"; diff --git a/web/client-v2/src/features/myFeeds/components/Template/MyFeedFolderArticleListTemplate/MyFeedFolderArticleListTemplate.tsx b/web/client-v2/src/features/myFeeds/components/Template/MyFeedFolderArticleListTemplate/MyFeedFolderArticleListTemplate.tsx index 8e60d3b7..85b455f8 100644 --- a/web/client-v2/src/features/myFeeds/components/Template/MyFeedFolderArticleListTemplate/MyFeedFolderArticleListTemplate.tsx +++ b/web/client-v2/src/features/myFeeds/components/Template/MyFeedFolderArticleListTemplate/MyFeedFolderArticleListTemplate.tsx @@ -13,6 +13,7 @@ import { import { getMyFeedFolderArticleListTemplateQuery } from "./actGetMyFeedFolderArticleListTemplateQuery"; import { MyFeedFolderArticleListTemplateQuery } from "./MyFeedFolderArticleListTemplateQuery"; +import { SearchMyFeedFolderArticleDialog } from "../../Dialog"; import { MyFeedFolderArticleList } from "../../List"; import { MyFeedFolderArticleKeywordSearchForm } from "../../Search"; @@ -104,10 +105,10 @@ export const MyFeedFolderArticleListTemplate: FC<
- {/* */} + />
); From f765cf2277c507ba0d6f6343a355d6ecb86131d1 Mon Sep 17 00:00:00 2001 From: YukiOnishi <58220747+YukiOnishi1129@users.noreply.github.com> Date: Sat, 4 Jan 2025 17:45:40 +0900 Subject: [PATCH 17/19] SearchMyFeedFolderDialog --- .../SearchMyFeedFolderDialog.tsx | 37 ++++++++ .../SearchMyFeedFolderDialogContent.tsx | 94 +++++++++++++++++++ .../Dialog/SearchMyFeedFolderDialog/index.ts | 1 + .../myFeeds/components/Dialog/index.ts | 1 + .../MyFeedFolderListTemplate.tsx | 11 ++- 5 files changed, 140 insertions(+), 4 deletions(-) create mode 100644 web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderDialog/SearchMyFeedFolderDialog.tsx create mode 100644 web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderDialog/SearchMyFeedFolderDialogContent.tsx create mode 100644 web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderDialog/index.ts diff --git a/web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderDialog/SearchMyFeedFolderDialog.tsx b/web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderDialog/SearchMyFeedFolderDialog.tsx new file mode 100644 index 00000000..839918d8 --- /dev/null +++ b/web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderDialog/SearchMyFeedFolderDialog.tsx @@ -0,0 +1,37 @@ +"use client"; + +import { FC, useCallback, useState } from "react"; +import { FaSearch } from "react-icons/fa"; +import { z } from "zod"; + +import { Dialog, DialogTrigger } from "@/components/ui/dialog"; + +import { SearchMyFeedFolderDialogContent } from "./SearchMyFeedFolderDialogContent"; + +type SearchMyFeedFolderDialogProps = { + keyword?: string; +}; + +export const SearchMyFeedFolderDialog: FC = ({ + keyword, +}) => { + const [open, setOpen] = useState(false); + + const handleClose = useCallback(() => { + setOpen(false); + }, []); + + return ( + + + + + {open && ( + + )} + + ); +}; diff --git a/web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderDialog/SearchMyFeedFolderDialogContent.tsx b/web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderDialog/SearchMyFeedFolderDialogContent.tsx new file mode 100644 index 00000000..47934a66 --- /dev/null +++ b/web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderDialog/SearchMyFeedFolderDialogContent.tsx @@ -0,0 +1,94 @@ +"use client"; + +import { zodResolver } from "@hookform/resolvers/zod"; +import { usePathname, useRouter } from "next/navigation"; +import { FC, useCallback } from "react"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; + +import { + DialogContent, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { + Form, + FormField, + FormItem, + FormLabel, + FormControl, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; + +import { serverRevalidatePage } from "@/actions/actServerRevalidatePage"; + +const formSchema = z.object({ + keyword: z.string().optional(), +}); + +type SearchMyFeedFolderDialogContentProps = { + keyword?: string; + handleClose: () => void; +}; + +export const SearchMyFeedFolderDialogContent: FC< + SearchMyFeedFolderDialogContentProps +> = ({ keyword, handleClose }) => { + const pathname = usePathname(); + const router = useRouter(); + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues: { + keyword: keyword ?? "", + }, + }); + + const resetDialog = useCallback(() => { + form.reset(); + }, [form]); + + const onSubmit = async (values: z.infer) => { + let keywordPath = ""; + if (!!values.keyword && values.keyword.trim() !== "") { + keywordPath = `keyword=${values.keyword}`; + } + await serverRevalidatePage(pathname); + router.replace(`/my-feed?${keywordPath}`); + resetDialog(); + handleClose(); + }; + + return ( + + + {"Search"} + +
+
+ +
+ ( + + Keyword + + + + + + )} + /> +
+
+ +
+
+ ); +}; diff --git a/web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderDialog/index.ts b/web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderDialog/index.ts new file mode 100644 index 00000000..a1de5c4d --- /dev/null +++ b/web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderDialog/index.ts @@ -0,0 +1 @@ +export * from "./SearchMyFeedFolderDialog"; diff --git a/web/client-v2/src/features/myFeeds/components/Dialog/index.ts b/web/client-v2/src/features/myFeeds/components/Dialog/index.ts index 18ef0b1e..6253fced 100644 --- a/web/client-v2/src/features/myFeeds/components/Dialog/index.ts +++ b/web/client-v2/src/features/myFeeds/components/Dialog/index.ts @@ -2,4 +2,5 @@ export * from "./CreateMyFeedFolderDialog"; export * from "./UpdateMyFeedFolderDialog"; export * from "./ShowMyFeedListDialog"; +export * from "./SearchMyFeedFolderDialog"; export * from "./SearchMyFeedFolderArticleDialog"; diff --git a/web/client-v2/src/features/myFeeds/components/Template/MyFeedFolderListTemplate/MyFeedFolderListTemplate.tsx b/web/client-v2/src/features/myFeeds/components/Template/MyFeedFolderListTemplate/MyFeedFolderListTemplate.tsx index b1ebfdd4..458241cc 100644 --- a/web/client-v2/src/features/myFeeds/components/Template/MyFeedFolderListTemplate/MyFeedFolderListTemplate.tsx +++ b/web/client-v2/src/features/myFeeds/components/Template/MyFeedFolderListTemplate/MyFeedFolderListTemplate.tsx @@ -5,7 +5,10 @@ import { ScreenLoader } from "@/components/layout/ScreenLoader"; import { PreloadQuery } from "@/lib/apollo/client"; import { MyFeedFolderListTemplateQuery } from "./MyFeedFolderListTemplateQuery"; -import { CreateMyFeedFolderDialog } from "../../Dialog"; +import { + CreateMyFeedFolderDialog, + SearchMyFeedFolderDialog, +} from "../../Dialog"; import { MyFeedFolderList } from "../../List"; import { MyFeedFolderKeywordSearchForm } from "../../Search"; @@ -56,9 +59,9 @@ export const MyFeedFolderListTemplate: FC = ({ - {/*
- -
*/} +
+ +
); }; From 813695f1855c8ae363a19760e1cb75bf8445834e Mon Sep 17 00:00:00 2001 From: YukiOnishi <58220747+YukiOnishi1129@users.noreply.github.com> Date: Sat, 4 Jan 2025 17:47:39 +0900 Subject: [PATCH 18/19] fix --- .../feeds/components/List/FeedArticleList/FeedArticleList.tsx | 2 +- .../SearchMyFeedFolderDialog/SearchMyFeedFolderDialog.tsx | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/web/client-v2/src/features/feeds/components/List/FeedArticleList/FeedArticleList.tsx b/web/client-v2/src/features/feeds/components/List/FeedArticleList/FeedArticleList.tsx index bdad5d37..2fb712b6 100644 --- a/web/client-v2/src/features/feeds/components/List/FeedArticleList/FeedArticleList.tsx +++ b/web/client-v2/src/features/feeds/components/List/FeedArticleList/FeedArticleList.tsx @@ -95,7 +95,7 @@ export function FeedArticleList({ id, keyword }: FeedArticleListProps) { setIsNextPage(resData.articles.pageInfo.hasNextPage); setHashMore(resData.articles.edges.length > 0); - }, [id, endCursor, isNextPage, fetchMore]); + }, [id, endCursor, isNextPage, fetchMore, keyword]); useEffect(() => { const observer = new IntersectionObserver( diff --git a/web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderDialog/SearchMyFeedFolderDialog.tsx b/web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderDialog/SearchMyFeedFolderDialog.tsx index 839918d8..ee33ce91 100644 --- a/web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderDialog/SearchMyFeedFolderDialog.tsx +++ b/web/client-v2/src/features/myFeeds/components/Dialog/SearchMyFeedFolderDialog/SearchMyFeedFolderDialog.tsx @@ -2,7 +2,6 @@ import { FC, useCallback, useState } from "react"; import { FaSearch } from "react-icons/fa"; -import { z } from "zod"; import { Dialog, DialogTrigger } from "@/components/ui/dialog"; From 5066b2718352d7146b1bc33ee02d5b44c5d22ea7 Mon Sep 17 00:00:00 2001 From: YukiOnishi <58220747+YukiOnishi1129@users.noreply.github.com> Date: Sat, 4 Jan 2025 17:56:17 +0900 Subject: [PATCH 19/19] fix bottom --- .../NotLoggedBaseLayout.tsx | 5 ++-- .../NotLoggedBottomNavigationMenu.tsx | 25 +++++++++++++++++++ .../NotLoggedBottomNavigationMenu/index.ts | 1 + .../layout/BottomNavigationMenu/index.ts | 1 + .../Header/MobileHeader/MobileHeader.tsx | 16 +++++++----- 5 files changed, 40 insertions(+), 8 deletions(-) create mode 100644 web/client-v2/src/components/layout/BottomNavigationMenu/NotLoggedBottomNavigationMenu/NotLoggedBottomNavigationMenu.tsx create mode 100644 web/client-v2/src/components/layout/BottomNavigationMenu/NotLoggedBottomNavigationMenu/index.ts diff --git a/web/client-v2/src/components/layout/BaseLayout/NotLoggedBaseLayout/NotLoggedBaseLayout.tsx b/web/client-v2/src/components/layout/BaseLayout/NotLoggedBaseLayout/NotLoggedBaseLayout.tsx index c3092087..af270a14 100644 --- a/web/client-v2/src/components/layout/BaseLayout/NotLoggedBaseLayout/NotLoggedBaseLayout.tsx +++ b/web/client-v2/src/components/layout/BaseLayout/NotLoggedBaseLayout/NotLoggedBaseLayout.tsx @@ -1,5 +1,6 @@ import { FC, ReactNode } from "react"; +import { NotLoggedBottomNavigationMenu } from "../../BottomNavigationMenu"; import { Header } from "../../Header"; type NotLoggedBaseLayoutProps = { @@ -20,9 +21,9 @@ export const NotLoggedBaseLayout: FC = async ({
{children}
- {/*
+
-
*/} +
); }; diff --git a/web/client-v2/src/components/layout/BottomNavigationMenu/NotLoggedBottomNavigationMenu/NotLoggedBottomNavigationMenu.tsx b/web/client-v2/src/components/layout/BottomNavigationMenu/NotLoggedBottomNavigationMenu/NotLoggedBottomNavigationMenu.tsx new file mode 100644 index 00000000..76e59a86 --- /dev/null +++ b/web/client-v2/src/components/layout/BottomNavigationMenu/NotLoggedBottomNavigationMenu/NotLoggedBottomNavigationMenu.tsx @@ -0,0 +1,25 @@ +"use client"; +import Link from "next/link"; +import { CiLogin } from "react-icons/ci"; +import { IoHomeSharp } from "react-icons/io5"; + +export const NotLoggedBottomNavigationMenu = () => { + return ( +
+
+ + + +
+ +
+ + + +
+
+ ); +}; diff --git a/web/client-v2/src/components/layout/BottomNavigationMenu/NotLoggedBottomNavigationMenu/index.ts b/web/client-v2/src/components/layout/BottomNavigationMenu/NotLoggedBottomNavigationMenu/index.ts new file mode 100644 index 00000000..20776835 --- /dev/null +++ b/web/client-v2/src/components/layout/BottomNavigationMenu/NotLoggedBottomNavigationMenu/index.ts @@ -0,0 +1 @@ +export * from "./NotLoggedBottomNavigationMenu"; diff --git a/web/client-v2/src/components/layout/BottomNavigationMenu/index.ts b/web/client-v2/src/components/layout/BottomNavigationMenu/index.ts index 5bf02503..c6936823 100644 --- a/web/client-v2/src/components/layout/BottomNavigationMenu/index.ts +++ b/web/client-v2/src/components/layout/BottomNavigationMenu/index.ts @@ -1 +1,2 @@ export * from "./LoggedBottomNavigationMenu"; +export * from "./NotLoggedBottomNavigationMenu"; diff --git a/web/client-v2/src/components/layout/Header/MobileHeader/MobileHeader.tsx b/web/client-v2/src/components/layout/Header/MobileHeader/MobileHeader.tsx index 48e13cbc..13518c2d 100644 --- a/web/client-v2/src/components/layout/Header/MobileHeader/MobileHeader.tsx +++ b/web/client-v2/src/components/layout/Header/MobileHeader/MobileHeader.tsx @@ -53,14 +53,18 @@ export const MobileHeader: FC = ({ user }) => { return (
-
- -
+ {user && ( +
+ +
+ )}

{pageName}

-
- -
+ {user && ( +
+ +
+ )}
); };