From 5c7b5223198fa2f0506552c3ee5b0af1fff4d010 Mon Sep 17 00:00:00 2001 From: Serhii Ofii <132130496+SnowGlowedMountain@users.noreply.github.com> Date: Mon, 14 Oct 2024 17:16:26 +0300 Subject: [PATCH] Serhii milestone 2 fix (#46) * chores_lint_errors_and_path_issues * feature_db_py * fix_audio_issue * chores_lint_error * fix_openAPI_switching * chore_module_insert * fix_edit_collection_fix * fix_frontend_critical_update --- frontend/package-lock.json | 217 ----- frontend/package.json | 2 - frontend/src/App.css | 90 ++- frontend/src/App.tsx | 12 +- frontend/src/ProtectedRoute.tsx | 19 +- frontend/src/components/Audio.tsx | 52 +- frontend/src/components/Book.tsx | 91 +++ frontend/src/components/BookSkeleton.tsx | 40 + frontend/src/components/HOC/Container.tsx | 10 + frontend/src/components/HOC/Content.tsx | 15 + .../src/components/HOC/DraggableWrapper.tsx | 78 ++ frontend/src/components/Logo.tsx | 14 + frontend/src/components/UploadContent.tsx | 6 +- .../components/auth/GoogleAuthComponent.tsx | 89 --- .../components/auth/RequireAuthentication.tsx | 22 - frontend/src/components/card.tsx | 2 +- frontend/src/components/collection/Edit.tsx | 350 ++++++++ frontend/src/components/collection/New.tsx | 62 ++ frontend/src/components/collection/View.tsx | 170 ++++ frontend/src/components/image.tsx | 6 - frontend/src/components/modal.tsx | 6 +- frontend/src/components/nav/Navbar.tsx | 107 +++ frontend/src/components/nav/TopNavbar.tsx | 123 --- frontend/src/components/new_card.tsx | 19 +- frontend/src/contexts/AuthContext.tsx | 7 +- frontend/src/contexts/api.tsx | 18 - frontend/src/gen/api.ts | 750 +++--------------- frontend/src/hooks/alerts.tsx | 81 +- frontend/src/hooks/auth.tsx | 144 ---- frontend/src/hooks/theme.tsx | 2 +- frontend/src/images/KScaleASCII.png | Bin 0 -> 58574 bytes frontend/src/images/KScaleASCIIMobile.png | Bin 0 -> 42819 bytes frontend/src/images/bookplaceholder.png | Bin 0 -> 298586 bytes frontend/src/images/small-logo.png | Bin 0 -> 25094 bytes frontend/src/pages/Collection.tsx | 541 ++----------- frontend/src/pages/Collections.tsx | 56 +- frontend/src/pages/Home.tsx | 134 +++- frontend/src/pages/Login.tsx | 26 +- frontend/src/pages/NotFound.tsx | 10 +- frontend/src/pages/Subscription.tsx | 23 +- frontend/src/types/model.ts | 3 + frontend/tailwind.config.js | 50 +- linguaphoto/api/collection.py | 28 +- linguaphoto/crud/base.py | 2 +- linguaphoto/crud/collection.py | 9 + linguaphoto/models.py | 2 + linguaphoto/schemas/collection.py | 6 + 47 files changed, 1557 insertions(+), 1937 deletions(-) create mode 100644 frontend/src/components/Book.tsx create mode 100644 frontend/src/components/BookSkeleton.tsx create mode 100644 frontend/src/components/HOC/Container.tsx create mode 100644 frontend/src/components/HOC/Content.tsx create mode 100644 frontend/src/components/HOC/DraggableWrapper.tsx create mode 100644 frontend/src/components/Logo.tsx delete mode 100644 frontend/src/components/auth/GoogleAuthComponent.tsx delete mode 100644 frontend/src/components/auth/RequireAuthentication.tsx create mode 100644 frontend/src/components/collection/Edit.tsx create mode 100644 frontend/src/components/collection/New.tsx create mode 100644 frontend/src/components/collection/View.tsx create mode 100644 frontend/src/components/nav/Navbar.tsx delete mode 100644 frontend/src/components/nav/TopNavbar.tsx delete mode 100644 frontend/src/hooks/auth.tsx create mode 100644 frontend/src/images/KScaleASCII.png create mode 100644 frontend/src/images/KScaleASCIIMobile.png create mode 100644 frontend/src/images/bookplaceholder.png create mode 100644 frontend/src/images/small-logo.png diff --git a/frontend/package-lock.json b/frontend/package-lock.json index da2f963..79ac845 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -44,7 +44,6 @@ "@types/jest": "^29.5.12", "axios": "^1.7.2", "babel-eslint": "*", - "bootstrap": "^5.3.3", "eslint": "^8.0.0", "eslint-config-prettier": "*", "eslint-import-resolver-typescript": "*", @@ -56,7 +55,6 @@ "nodemon": "^3.1.0", "prettier": "^3.2.5", "prettier-plugin-organize-imports": "^3.2.4", - "react-bootstrap": "^2.10.2", "react-router-dom": "^6.23.1", "tailwindcss": "^3.4.10", "ts-jest": "^29.2.5", @@ -3602,31 +3600,6 @@ "node": ">= 8" } }, - "node_modules/@popperjs/core": { - "version": "2.11.8", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", - "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" - } - }, - "node_modules/@react-aria/ssr": { - "version": "3.9.5", - "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.5.tgz", - "integrity": "sha512-xEwGKoysu+oXulibNUSkXf8itW0npHHTa6c4AyYeZIJyRoegeteYuFpZUBPtIDE8RfHdNsSmE1ssOkxRnwbkuQ==", - "dev": true, - "dependencies": { - "@swc/helpers": "^0.5.0" - }, - "engines": { - "node": ">= 12" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" - } - }, "node_modules/@react-oauth/google": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/@react-oauth/google/-/google-0.12.1.tgz", @@ -3646,48 +3619,6 @@ "node": ">=14.0.0" } }, - "node_modules/@restart/hooks": { - "version": "0.4.16", - "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz", - "integrity": "sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==", - "dev": true, - "dependencies": { - "dequal": "^2.0.3" - }, - "peerDependencies": { - "react": ">=16.8.0" - } - }, - "node_modules/@restart/ui": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.8.0.tgz", - "integrity": "sha512-xJEOXUOTmT4FngTmhdjKFRrVVF0hwCLNPdatLCHkyS4dkiSK12cEu1Y0fjxktjJrdst9jJIc5J6ihMJCoWEN/g==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.21.0", - "@popperjs/core": "^2.11.6", - "@react-aria/ssr": "^3.5.0", - "@restart/hooks": "^0.4.9", - "@types/warning": "^3.0.0", - "dequal": "^2.0.3", - "dom-helpers": "^5.2.0", - "uncontrollable": "^8.0.1", - "warning": "^4.0.3" - }, - "peerDependencies": { - "react": ">=16.14.0", - "react-dom": ">=16.14.0" - } - }, - "node_modules/@restart/ui/node_modules/uncontrollable": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.4.tgz", - "integrity": "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==", - "dev": true, - "peerDependencies": { - "react": ">=16.14.0" - } - }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -4055,15 +3986,6 @@ "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@swc/helpers": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.13.tgz", - "integrity": "sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==", - "dev": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@testing-library/dom": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", @@ -4645,15 +4567,6 @@ "@types/react": "*" } }, - "node_modules/@types/react-transition-group": { - "version": "4.4.11", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz", - "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==", - "dev": true, - "dependencies": { - "@types/react": "*" - } - }, "node_modules/@types/resolve": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", @@ -4725,12 +4638,6 @@ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==" }, - "node_modules/@types/warning": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz", - "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==", - "dev": true - }, "node_modules/@types/ws": { "version": "8.5.12", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", @@ -6142,25 +6049,6 @@ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" }, - "node_modules/bootstrap": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", - "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/twbs" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/bootstrap" - } - ], - "peerDependencies": { - "@popperjs/core": "^2.11.8" - } - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -6437,12 +6325,6 @@ "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz", "integrity": "sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==" }, - "node_modules/classnames": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", - "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", - "dev": true - }, "node_modules/clean-css": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", @@ -7542,16 +7424,6 @@ "utila": "~0.4" } }, - "node_modules/dom-helpers": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", - "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.8.7", - "csstype": "^3.0.2" - } - }, "node_modules/dom-serializer": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", @@ -16049,25 +15921,6 @@ "react-is": "^16.13.1" } }, - "node_modules/prop-types-extra": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", - "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", - "dev": true, - "dependencies": { - "react-is": "^16.3.2", - "warning": "^4.0.0" - }, - "peerDependencies": { - "react": ">=0.14.0" - } - }, - "node_modules/prop-types-extra/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - }, "node_modules/prop-types/node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -16359,36 +16212,6 @@ "uuid": "bin/uuid" } }, - "node_modules/react-bootstrap": { - "version": "2.10.4", - "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.4.tgz", - "integrity": "sha512-W3398nBM2CBfmGP2evneEO3ZZwEMPtHs72q++eNw60uDGDAdiGn0f9yNys91eo7/y8CTF5Ke1C0QO8JFVPU40Q==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.24.7", - "@restart/hooks": "^0.4.9", - "@restart/ui": "^1.6.9", - "@types/react-transition-group": "^4.4.6", - "classnames": "^2.3.2", - "dom-helpers": "^5.2.1", - "invariant": "^2.2.4", - "prop-types": "^15.8.1", - "prop-types-extra": "^1.1.0", - "react-transition-group": "^4.4.5", - "uncontrollable": "^7.2.1", - "warning": "^4.0.3" - }, - "peerDependencies": { - "@types/react": ">=16.14.8", - "react": ">=16.14.0", - "react-dom": ">=16.14.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/react-bootstrap-icons": { "version": "1.11.4", "resolved": "https://registry.npmjs.org/react-bootstrap-icons/-/react-bootstrap-icons-1.11.4.tgz", @@ -17988,22 +17811,6 @@ "node": ">=10" } }, - "node_modules/react-transition-group": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", - "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.5.5", - "dom-helpers": "^5.0.1", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2" - }, - "peerDependencies": { - "react": ">=16.6.0", - "react-dom": ">=16.6.0" - } - }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -20494,21 +20301,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/uncontrollable": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", - "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.6.3", - "@types/react": ">=16.9.11", - "invariant": "^2.2.4", - "react-lifecycles-compat": "^3.0.4" - }, - "peerDependencies": { - "react": ">=15.0.0" - } - }, "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", @@ -20734,15 +20526,6 @@ "makeerror": "1.0.12" } }, - "node_modules/warning": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", - "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", - "dev": true, - "dependencies": { - "loose-envify": "^1.0.0" - } - }, "node_modules/watchpack": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index 1b0c51a..5cb1a8d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -61,7 +61,6 @@ "@types/jest": "^29.5.12", "axios": "^1.7.2", "babel-eslint": "*", - "bootstrap": "^5.3.3", "eslint": "^8.0.0", "eslint-config-prettier": "*", "eslint-import-resolver-typescript": "*", @@ -73,7 +72,6 @@ "nodemon": "^3.1.0", "prettier": "^3.2.5", "prettier-plugin-organize-imports": "^3.2.4", - "react-bootstrap": "^2.10.2", "react-router-dom": "^6.23.1", "tailwindcss": "^3.4.10", "ts-jest": "^29.2.5", diff --git a/frontend/src/App.css b/frontend/src/App.css index 56f0752..43ca4da 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -4,5 +4,93 @@ @tailwind utilities; body { - font-family: "Noto Serif SC", serif; /* Use Noto Serif Simplified Chinese font */ + font-family: "Noto Serif SC", serif; + /* Use Noto Serif Simplified Chinese font */ +} + +.perspective { + perspective: 1000px; +} + +.transform-style-preserve-3d { + transform-style: preserve-3d; +} + +.backface-hidden { + backface-visibility: hidden; +} + +.group-hover\:rotate-y-30:hover, +.rotate-y-30 { + transform: rotateY(-30deg); + /* Rotate the element on hover */ +} + +.rotate-y-90 { + transform: rotateY(-90deg) !important; +} + +.rotate-y-180 { + transform: rotateY(180deg); +} + +.rotate-left { + transform-origin: left; + /* Set transform origin to the left edge */ +} + +@layer base { + @layer base { + /* Global input customization */ + input, + textarea, + select { + @apply border border-gray-300 rounded-lg px-4 py-2 bg-white text-black placeholder-gray-400 transition duration-200 ease-in-out; + } + + /* Hover and focus states for inputs */ + input:hover, + textarea:hover, + select:hover { + @apply border-gray-400; + } + + input:focus, + textarea:focus, + select:focus { + @apply border-blue-500 ring ring-blue-200 outline-none; + } + + /* Disabled input */ + input:disabled, + textarea:disabled, + select:disabled { + @apply bg-gray-200 cursor-not-allowed opacity-50; + } + + /* Additional customization for textareas */ + textarea { + @apply resize-none; + /* Prevents resizing */ + } + + /* Button styling */ + button { + @apply bg-blue-500 text-white px-6 py-2 rounded-lg transition duration-200 ease-in-out; + } + + /* Hover and focus states for buttons */ + button:hover { + @apply bg-blue-600; + } + + button:focus { + @apply ring ring-blue-300 outline-none; + } + + /* Disabled button */ + button:disabled { + @apply bg-gray-500 cursor-not-allowed opacity-50; + } + } } diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index d5175f8..b9cbbfe 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,6 +1,6 @@ -import "bootstrap/dist/css/bootstrap.min.css"; +import Content from "components/HOC/Content"; import LoadingMask from "components/LoadingMask"; -import TopNavbar from "components/nav/TopNavbar"; +import Navbar from "components/nav/Navbar"; import NotFoundRedirect from "components/NotFoundRedirect"; import { AuthProvider } from "contexts/AuthContext"; import { LoadingProvider } from "contexts/LoadingContext"; @@ -14,7 +14,6 @@ import NotFound from "pages/NotFound"; import SubscriptionTypePage from "pages/SubscriptioinType"; import SubscriptionCancelPage from "pages/Subscription"; import PrivateRoute from "ProtectedRoute"; -import { Container } from "react-bootstrap"; import { BrowserRouter as Router, Route, Routes } from "react-router-dom"; import "./App.css"; @@ -26,7 +25,7 @@ const App = () => { - + } /> } /> @@ -82,8 +81,9 @@ const App = () => { /> } /> - - + + + {/* */} diff --git a/frontend/src/ProtectedRoute.tsx b/frontend/src/ProtectedRoute.tsx index 438242c..42bfee8 100644 --- a/frontend/src/ProtectedRoute.tsx +++ b/frontend/src/ProtectedRoute.tsx @@ -11,20 +11,19 @@ const PrivateRoute: React.FC = ({ element, requiredSubscription = false, }) => { - const { auth } = useAuth(); + const { auth, is_auth } = useAuth(); const location = useLocation(); const navigate = useNavigate(); useEffect(() => { - if (auth) - if (!auth?.is_auth) { - // Redirect to login if not authenticated - navigate("/login", { replace: true, state: { from: location } }); - } else if (requiredSubscription && !auth?.is_subscription) { - // Redirect to subscription page if subscription is required and not active - navigate("/subscription_type", { replace: true }); - } - }, [auth, requiredSubscription, navigate, location]); + if (!is_auth) { + // Redirect to login if not authenticated + navigate("/login", { replace: true, state: { from: location } }); + } else if (auth && requiredSubscription && !auth?.is_subscription) { + // Redirect to subscription page if subscription is required and not active + navigate("/subscription_type", { replace: true }); + } + }, [auth, is_auth, requiredSubscription, navigate, location]); if (!auth?.is_auth || (requiredSubscription && !auth?.is_subscription)) { // Render nothing while redirecting diff --git a/frontend/src/components/Audio.tsx b/frontend/src/components/Audio.tsx index 5dea933..9d92b1f 100644 --- a/frontend/src/components/Audio.tsx +++ b/frontend/src/components/Audio.tsx @@ -1,4 +1,5 @@ import React, { useEffect, useRef, useState } from "react"; +import { CaretLeft, CaretRight } from "react-bootstrap-icons"; import { FaPause, FaPlay, @@ -9,15 +10,22 @@ import { import { Image } from "types/model"; interface AudioPlayerProps { - currentImage: Image; - index: number; + currentImage: Image; // current image + index: number; // current transcription index + handleTranscriptionNext: () => void; //next transcript + handleTranscriptionPrev: () => void; //prev transcript } -const AudioPlayer: React.FC = ({ currentImage, index }) => { - const audioRef = useRef(null); +const AudioPlayer: React.FC = ({ + currentImage, + index, + handleTranscriptionNext, + handleTranscriptionPrev, +}) => { + const audioRef = useRef(null); //audio const [isPlaying, setIsPlaying] = useState(false); - const [playbackRate, setPlaybackRate] = useState(1); - const [volume, setVolume] = useState(1); + const [playbackRate, setPlaybackRate] = useState(1); //speed + const [volume, setVolume] = useState(1); // volumn size const [currentTime, setCurrentTime] = useState(0); const [duration, setDuration] = useState(0); @@ -82,13 +90,15 @@ const AudioPlayer: React.FC = ({ currentImage, index }) => { setCurrentTime(0); // Reset current time to 0 }); + audio.addEventListener("ended", handleTranscriptionNext); + // Clean up the event listeners on component unmount return () => { audio.removeEventListener("timeupdate", () => {}); audio.removeEventListener("ended", () => {}); }; } - }, []); + }, [handleTranscriptionNext]); useEffect(() => { if (audioRef.current) { @@ -98,7 +108,7 @@ const AudioPlayer: React.FC = ({ currentImage, index }) => { }, [currentImage, index]); return ( -
+