From 4236cca96399e3530e261710ec5f0baf94dbb523 Mon Sep 17 00:00:00 2001 From: Ujjwal Date: Thu, 22 Feb 2024 01:55:34 +0530 Subject: [PATCH] mutlilanguage & gpt feature & header fixed --- .gitignore | 2 + README.md | 14 ++ package-lock.json | 291 +++++++++++++++++++++++++++++- package.json | 7 +- src/components/Browse.js | 15 +- src/components/GptContainer.js | 21 +++ src/components/GptMovie.js | 26 +++ src/components/GptSearch.js | 102 +++++++++++ src/components/Header.js | 77 ++++++-- src/components/Maincontainer.js | 2 +- src/components/MovieCard.js | 2 +- src/components/Movielist.js | 80 ++++++-- src/components/NotFoundPage.js | 26 +++ src/customHook/useMovieTrailer.js | 7 + src/notfound.css | 44 +++++ src/utils/appStore.js | 4 + src/utils/constant.js | 6 +- src/utils/gptMovieSlice.js | 29 +++ src/utils/langConfigSlice.js | 16 ++ src/utils/languageConstant.js | 12 ++ src/utils/openAI.js | 11 ++ 21 files changed, 761 insertions(+), 33 deletions(-) create mode 100644 src/components/GptContainer.js create mode 100644 src/components/GptMovie.js create mode 100644 src/components/GptSearch.js create mode 100644 src/components/NotFoundPage.js create mode 100644 src/notfound.css create mode 100644 src/utils/gptMovieSlice.js create mode 100644 src/utils/langConfigSlice.js create mode 100644 src/utils/languageConstant.js create mode 100644 src/utils/openAI.js diff --git a/.gitignore b/.gitignore index 4d29575..f64b4f2 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,8 @@ # production /build + +/.env # misc .DS_Store .env.local diff --git a/README.md b/README.md index 1d4a6f7..b658ea7 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,20 @@ - handling trailer video trough redux store - displaying trailer in background - displaying all category of movies & making more custom hooks +- mutlilinguistic +- gpt feature added using open ai API KEY +- fetched gptMoviesSuggestions from TMDB +- Header ui fixed +- beautiful error page +- asking user api key + +# To Do: +- not responsive(*) +- each card functionality +- test user already present + + + # features required: - login/sign up - login /sign up(if not authenticated user) diff --git a/package-lock.json b/package-lock.json index 6cda23e..3c413b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,13 +8,18 @@ "name": "netflixgpt", "version": "0.1.0", "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.5.1", + "@fortawesome/free-solid-svg-icons": "^6.5.1", + "@fortawesome/react-fontawesome": "^0.2.0", "@reduxjs/toolkit": "^2.2.1", "cra-template": "1.2.0", "firebase": "^10.8.0", + "openai": "^4.28.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-redux": "^9.1.0", - "react-scripts": "5.0.1" + "react-scripts": "5.0.1", + "swiper": "^11.0.6" }, "devDependencies": { "react-router-dom": "^6.22.1", @@ -2868,6 +2873,51 @@ "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.10.5.tgz", "integrity": "sha512-eSkJsnhBWv5kCTSU1tSUVl9mpFu+5NXXunZc83le8GMjMlsWwQArSc7cJJ4yl+aDFY0NGLi0AjZWMn1axOrkRg==" }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz", + "integrity": "sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.1.tgz", + "integrity": "sha512-MfRCYlQPXoLlpem+egxjfkEuP9UQswTrlCOsknus/NcMoblTH2g0jPrapbcIb04KGA7E2GZxbAccGZfWoYgsrQ==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.1.tgz", + "integrity": "sha512-S1PPfU3mIJa59biTtXJz1oI0+KAXW6bkAb31XKhxdxtuXDiUIFsih4JR1v5BbxY7hVHsD1RKq+jRkVRaf773NQ==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/react-fontawesome": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz", + "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==", + "dependencies": { + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6", + "react": ">=16.3" + } + }, "node_modules/@grpc/grpc-js": { "version": "1.9.14", "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.14.tgz", @@ -4507,6 +4557,28 @@ "undici-types": "~5.26.4" } }, + "node_modules/@types/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/node-fetch/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/@types/node-forge": { "version": "1.3.11", "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", @@ -4999,6 +5071,17 @@ "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", "deprecated": "Use your platform's native atob() and btoa() methods instead" }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -5097,6 +5180,17 @@ "node": ">= 6.0.0" } }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -5789,6 +5883,11 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base-64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", + "integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==" + }, "node_modules/batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", @@ -6100,6 +6199,14 @@ "node": ">=10" } }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "engines": { + "node": "*" + } + }, "node_modules/check-types": { "version": "11.2.3", "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.2.3.tgz", @@ -6456,6 +6563,14 @@ "node": ">= 8" } }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "engines": { + "node": "*" + } + }, "node_modules/crypto-random-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", @@ -7054,6 +7169,15 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, + "node_modules/digest-fetch": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/digest-fetch/-/digest-fetch-1.3.0.tgz", + "integrity": "sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA==", + "dependencies": { + "base-64": "^0.1.0", + "md5": "^2.3.0" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -8157,6 +8281,14 @@ "node": ">= 0.6" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "engines": { + "node": ">=6" + } + }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", @@ -8746,6 +8878,31 @@ "node": ">= 6" } }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==" + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, + "node_modules/formdata-node/node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "engines": { + "node": ">= 14" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -9400,6 +9557,14 @@ "node": ">=10.17.0" } }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dependencies": { + "ms": "^2.0.0" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -9615,6 +9780,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -12462,6 +12632,16 @@ "tmpl": "1.0.5" } }, + "node_modules/md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, "node_modules/mdn-data": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", @@ -12749,6 +12929,62 @@ "tslib": "^2.0.3" } }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -13019,6 +13255,33 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/openai": { + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.28.0.tgz", + "integrity": "sha512-JM8fhcpmpGN0vrUwGquYIzdcEQHtFuom6sRCbbCM6CfzZXNuRk33G7KfeRAIfnaCxSpzrP5iHtwJzIm6biUZ2Q==", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "digest-fetch": "^1.3.0", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7", + "web-streams-polyfill": "^3.2.1" + }, + "bin": { + "openai": "bin/cli" + } + }, + "node_modules/openai/node_modules/@types/node": { + "version": "18.19.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.17.tgz", + "integrity": "sha512-SzyGKgwPzuWp2SHhlpXKzCX0pIOfcI4V2eF37nNBJOhwlegQ83omtVQ1XxZpDE06V/d6AQvfQdPfnw0tRC//Ng==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -16649,6 +16912,24 @@ "boolbase": "~1.0.0" } }, + "node_modules/swiper": { + "version": "11.0.6", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.0.6.tgz", + "integrity": "sha512-W/Me7MQl5rNgdM5x9i3Gll76WsyVpnHn91GhBOyL7RCFUeg62aVnflzlVfIpXzZ/87FtJOfAoDH79ZH2Yq76zA==", + "funding": [ + { + "type": "patreon", + "url": "https://www.patreon.com/swiperjs" + }, + { + "type": "open_collective", + "url": "http://opencollective.com/swiper" + } + ], + "engines": { + "node": ">= 4.7.0" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -17384,6 +17665,14 @@ "minimalistic-assert": "^1.0.0" } }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "engines": { + "node": ">= 8" + } + }, "node_modules/webidl-conversions": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", diff --git a/package.json b/package.json index f6682be..96833ca 100644 --- a/package.json +++ b/package.json @@ -3,13 +3,18 @@ "version": "0.1.0", "private": true, "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.5.1", + "@fortawesome/free-solid-svg-icons": "^6.5.1", + "@fortawesome/react-fontawesome": "^0.2.0", "@reduxjs/toolkit": "^2.2.1", "cra-template": "1.2.0", "firebase": "^10.8.0", + "openai": "^4.28.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-redux": "^9.1.0", - "react-scripts": "5.0.1" + "react-scripts": "5.0.1", + "swiper": "^11.0.6" }, "scripts": { "start": "react-scripts start", diff --git a/src/components/Browse.js b/src/components/Browse.js index fe33e6e..e81e377 100644 --- a/src/components/Browse.js +++ b/src/components/Browse.js @@ -6,9 +6,13 @@ import Secondarycontainer from './Secondarycotainer'; import usePopularMovie from '../customHook/usePopularMovie'; import useTopRatedMovie from '../customHook/useTopRatedMovie'; import useUpcomingMovie from '../customHook/useUpcomingMovie'; +import { useSelector } from 'react-redux'; +import GptContainer from './GptContainer'; const Browse = () => { + const gptState=useSelector(store=>store.gptMovie.gptState); + // console.log(gptState); useNowPlayingMovies(); usePopularMovie(); useTopRatedMovie(); @@ -16,9 +20,14 @@ const Browse = () => { return (
- - - browse + { + gptState?: + <> + + + + } +
) } diff --git a/src/components/GptContainer.js b/src/components/GptContainer.js new file mode 100644 index 0000000..0e536d9 --- /dev/null +++ b/src/components/GptContainer.js @@ -0,0 +1,21 @@ +import GptMovie from "./GptMovie" +import GptSearch from "./GptSearch" +import { NETFLIX_BG} from "../utils/constant" + +const GptContainer = () => { + return ( + <> +
+ logo +
+
+ + {/*
Note: Movie recommendations powered by GPT are available on request due to paid APIs.
*/} + +
+ + + ) +} + +export default GptContainer diff --git a/src/components/GptMovie.js b/src/components/GptMovie.js new file mode 100644 index 0000000..2deb0e4 --- /dev/null +++ b/src/components/GptMovie.js @@ -0,0 +1,26 @@ +import { useSelector } from "react-redux" +import Movielist from "./Movielist"; + +const GptMovie = () => { + const gptMovie=useSelector( store =>store.gptMovie); + + const {gptMovieName,gptMovieResult}=gptMovie; + if (!gptMovieName) return null; + return ( +
+ +
+ {gptMovieName.map((movieName, index) => ( + + ))} +
+
+ ) +} + + +export default GptMovie diff --git a/src/components/GptSearch.js b/src/components/GptSearch.js new file mode 100644 index 0000000..45ba186 --- /dev/null +++ b/src/components/GptSearch.js @@ -0,0 +1,102 @@ +import { useRef } from "react"; +// import openai from "../utils/openAI"; +import { MOVIE_API_OPTION } from "../utils/constant"; +import { useDispatch, useSelector } from "react-redux"; +import { setGptMovie, setUserApiKey } from "../utils/gptMovieSlice"; +import language from "../utils/languageConstant"; +import OpenAI from "openai"; +import NotFoundPage from "./NotFoundPage"; + +const GptSearch = () => { + + const val=useRef(); + const apikeyval=useRef(); + const lang=useSelector(state=>state.langConfig.language); + const userAPIKEY=useSelector(store=>store.gptMovie.userApiKey); + const dispatch=useDispatch(); + + const searchMovieTMDB=async (movie)=>{ + const data=await fetch("https://api.themoviedb.org/3/search/movie?query="+movie+"&include_adult=false&language=en-US&page=1",MOVIE_API_OPTION ) + const json=await data.json(); + return json.results; + } + + const handleClick=async ()=>{ + + const searchText=val.current.value; + + + const gptQuery = + "Act as a Movie Recommendation system and suggest some movies for the query : " + + searchText + + ". only give me names of 5 movies, comma seperated like the example result given ahead. Example Result: Gadar, Sholay, Don, Golmaal, Koi Mil Gaya"; + // commented + try{ + + const openai = new OpenAI({ + apiKey: userAPIKEY , + dangerouslyAllowBrowser: true, + // This is the default and can be omitted + }); + + const gptResults = await openai.chat.completions.create({ + messages: [{ role: "user", content: gptQuery }], + model: "gpt-3.5-turbo", + }); + console.log(gptResults); + // if(gptResults) + + + const gptMovies=gptResults.choices?.[0]?.message?.content.split(", "); + + // const gptMovies=["Stree", "Bhool Bhulaiyaa", "Go Goa Gone", "Roohi", "Bhoot Police"]; + const promiseArray = gptMovies.map((movie) => searchMovieTMDB(movie)); + // [Promise, Promise, Promise, Promise, Promise] + + // to resolve all movies + const tmdbResults = await Promise.all(promiseArray); + console.log(tmdbResults); + dispatch(setGptMovie({movieName:gptMovies,movieResult:tmdbResults})); + } + catch(error) + { + return + } + + + // console.log(tmdbResults); + } + + return ( +
+
ev.preventDefault()}> + + + + dispatch(setUserApiKey(e.target.value))} + /> + +
+ +
+ ) +} + +export default GptSearch diff --git a/src/components/Header.js b/src/components/Header.js index 46c61a8..c330cde 100644 --- a/src/components/Header.js +++ b/src/components/Header.js @@ -8,10 +8,15 @@ import {onAuthStateChanged } from "firebase/auth"; import { useDispatch } from 'react-redux'; import { addUser, removeUser } from '../utils/userSlice'; import { useEffect } from 'react'; +import { setGptState } from '../utils/gptMovieSlice'; +import { setLanguage } from '../utils/langConfigSlice'; +import { useState } from 'react'; const Header = () => { - const dispatch =useDispatch(); + const gptState=useSelector(store=> store.gptMovie.gptState); const user=useSelector(store=>store.user); - const navigate=useNavigate() + const [isDropdownOpen, setIsDropdownOpen] = useState(false); + const dispatch =useDispatch(); + const navigate=useNavigate(); const handleSignout=()=>{ signOut(auth).then(() => { // Sign-out successful. @@ -19,14 +24,31 @@ const Header = () => { }).catch((error) => { // An error happened. navigate('/error'); - + }); } - + const handleGptClick=()=>{ + // console.log("btn clicked"); + dispatch(setGptState()); + } + // + const handleLanguageChange=(e)=>{ + // console.log(e.target.value); + dispatch(setLanguage(e.target.value)); + + // console.log(lang); + } + + const handleLogoClick=()=>{ + if(gptState) + dispatch(setGptState()); + + } + useEffect(()=>{ // console.log("useffect"); - const unSubscribe= onAuthStateChanged(auth, (user) => { + const unSubscribe= onAuthStateChanged(auth, (user) => { if (user) { const { uid ,displayName, email, photoURL }= user; dispatch((addUser({uid:uid, displayName:displayName,email:email ,photoURL:photoURL}))); @@ -44,21 +66,52 @@ const Header = () => { return ( -
- + logo {user &&
- user-icon + \ + Search + + } + {gptState && + + + } + + user-icon setIsDropdownOpen(!isDropdownOpen)} src={AVATAR} /> - + */} + + {isDropdownOpen && ( +
+ +
+ )} +
}
diff --git a/src/components/Maincontainer.js b/src/components/Maincontainer.js index 79eedde..fac6d65 100644 --- a/src/components/Maincontainer.js +++ b/src/components/Maincontainer.js @@ -6,7 +6,7 @@ import Videotitle from "./Videotitle" const Maincontainer=()=>{ const movie=useSelector((store)=> store.movie?.nowPlayingMovies); if(!movie) return ; - const mainMovie=movie[0]; + const mainMovie=movie[1]; // console.log(mainMovie) const { title ,overview ,id }=mainMovie; // console.log(title,overview); diff --git a/src/components/MovieCard.js b/src/components/MovieCard.js index 114ac07..56acc4b 100644 --- a/src/components/MovieCard.js +++ b/src/components/MovieCard.js @@ -4,7 +4,7 @@ import { POSTER_PATH_CDN } from '../utils/constant'; const MovieCard = ({poster_path}) => { if (!poster_path) return null; return ( -
+
movie-poster
) diff --git a/src/components/Movielist.js b/src/components/Movielist.js index 59be30b..e40a487 100644 --- a/src/components/Movielist.js +++ b/src/components/Movielist.js @@ -1,18 +1,74 @@ -import React from 'react' + import MovieCard from './MovieCard'; +import React, { useRef, useState } from 'react'; +// Import Swiper React components +import { Swiper, SwiperSlide } from 'swiper/react'; + +// Import Swiper styles +import 'swiper/css'; +import 'swiper/css/pagination'; + + + +// import required modules +import { Keyboard, Pagination, Navigation,Mousewheel } from 'swiper/modules'; + + const Movielist = ({title, movies}) => { -return ( -
-

{title}

-
-
- {movies?.map((movie) => ( - - ))} + + + + return ( + <> +
+

{title}

+ + + + {movies?.map((movie) => ( + + + + ))} +
-
-
- ); + + ) } export default Movielist + +// return ( +//
+//

{title}

+//
+//
+// {movies?.map((movie) => ( +// +// ))} +//
+//
+//
+// ); + + +// {movies?.map((movie) => ( +// +// +// +// ))} \ No newline at end of file diff --git a/src/components/NotFoundPage.js b/src/components/NotFoundPage.js new file mode 100644 index 0000000..f1e3030 --- /dev/null +++ b/src/components/NotFoundPage.js @@ -0,0 +1,26 @@ +import '../notfound.css'; + +const NotFoundPage = () => { + return ( +
+
+
+
+
+
+

404

+
+
+

Look like you're lost

+

The page you are looking for is not available!

+ Go to Home +
+
+
+
+
+
+ ); +}; + +export default NotFoundPage; diff --git a/src/customHook/useMovieTrailer.js b/src/customHook/useMovieTrailer.js index ed468f2..aadffa8 100644 --- a/src/customHook/useMovieTrailer.js +++ b/src/customHook/useMovieTrailer.js @@ -2,15 +2,22 @@ import { addTrailerVideo } from '../utils/movieSlice'; import { MOVIE_API_OPTION } from '../utils/constant'; import { useEffect } from 'react'; import { useDispatch } from 'react-redux'; +import NotFoundPage from '../components/NotFoundPage'; const useMovieTrailer = (id) => { const dispatch=useDispatch(); const getmovieVideo=async ()=>{ + try{ const data= await fetch("https://api.themoviedb.org/3/movie/"+id+"/videos?language=en-US", MOVIE_API_OPTION) const json= await data.json(); const filterData=json.results.filter(video => video.type==="Trailer") const trailer=filterData.length? filterData[0]:json.results[0]; dispatch(addTrailerVideo(trailer)) } + catch(err) + { + return + } + } useEffect(()=>{ getmovieVideo(); diff --git a/src/notfound.css b/src/notfound.css new file mode 100644 index 0000000..3143475 --- /dev/null +++ b/src/notfound.css @@ -0,0 +1,44 @@ + +.page_404 { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + padding: 40px 0; + background: #fff; + color: #000; + font-family: 'Arial', serif; + } + + .page_404 img { + width: 100%; + } + + .four_zero_four_bg { + + background-image: url(https://cdn.dribbble.com/users/285475/screenshots/2083086/dribbble_1.gif); + height: 400px; + background-position: center; + } + + + .four_zero_four_bg h1 { + font-size: 80px; + } + + .four_zero_four_bg h3 { + font-size: 80px; + } + + .link_404 { + color: #fff !important; + padding: 10px 20px; + background: #e50815; + margin: 20px 0; + display: inline-block; + } + + .contant_box_404 { + margin-top: -50px; + } + \ No newline at end of file diff --git a/src/utils/appStore.js b/src/utils/appStore.js index 0e5f6d4..2c67317 100644 --- a/src/utils/appStore.js +++ b/src/utils/appStore.js @@ -1,10 +1,14 @@ import { configureStore } from "@reduxjs/toolkit"; import userReducer from "./userSlice" import movieReducer from "./movieSlice" +import gptReducer from "./gptMovieSlice" +import langConfigReducer from "./langConfigSlice" const appStore=configureStore({ reducer:{ user: userReducer, movie:movieReducer, + gptMovie:gptReducer, + langConfig:langConfigReducer, } }) diff --git a/src/utils/constant.js b/src/utils/constant.js index e0f148b..e75e4d8 100644 --- a/src/utils/constant.js +++ b/src/utils/constant.js @@ -11,9 +11,11 @@ export const MOVIE_API_OPTION = { method: 'GET', headers: { accept: 'application/json', - Authorization: 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJlNDBkMzYzMTFlY2NmYWUxNDQ2ZDg3ZmVmNDkzZThhYSIsInN1YiI6IjY1ZDMxZjM5NGJjMzhiMDE4OTU1MzA2ZSIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.Mgj7uyWAiE27gA0u1LpwiEdnUnl7dEmi3pIs-24jAGY' + Authorization: "Bearer"+ process.env.TMDB_API, } }; export const POSTER_PATH_CDN= - "https://image.tmdb.org/t/p/original"; \ No newline at end of file + "https://image.tmdb.org/t/p/original"; + + diff --git a/src/utils/gptMovieSlice.js b/src/utils/gptMovieSlice.js new file mode 100644 index 0000000..9e4348f --- /dev/null +++ b/src/utils/gptMovieSlice.js @@ -0,0 +1,29 @@ +import { createSlice } from "@reduxjs/toolkit"; + +const gptMovieSlice=createSlice({ + name:"gptMovie", + initialState:{ + gptState:false, + gptMovieResult:null, + gptMovieName:null, + userApiKey:null, + }, + reducers:{ + setGptState:(state)=> + { + state.gptState=!state.gptState; + }, + setGptMovie:(state,action)=> + { + const {movieName,movieResult}=action.payload; + state.gptMovieResult=movieResult; + state.gptMovieName=movieName; + }, + setUserApiKey:(state,action)=>{ + state.userApiKey=action.payload + } + } +}) + +export const {setGptState,setGptMovie,setUserApiKey}=gptMovieSlice.actions; +export default gptMovieSlice.reducer; \ No newline at end of file diff --git a/src/utils/langConfigSlice.js b/src/utils/langConfigSlice.js new file mode 100644 index 0000000..973196d --- /dev/null +++ b/src/utils/langConfigSlice.js @@ -0,0 +1,16 @@ +import { createSlice } from "@reduxjs/toolkit"; + +const langConfig=createSlice({ + name:"langConfig", + initialState:{ + language:"English", + }, + reducers:{ + setLanguage:(state,action)=>{ + state.language=action.payload; + } + } +}) + +export const { setLanguage }=langConfig.actions; +export default langConfig.reducer; \ No newline at end of file diff --git a/src/utils/languageConstant.js b/src/utils/languageConstant.js new file mode 100644 index 0000000..47e6cf1 --- /dev/null +++ b/src/utils/languageConstant.js @@ -0,0 +1,12 @@ +const language={ + "English":{ + search:"Search", + gptPlaceHolder:"Use GPT as movie recommendations ..." + }, + "हिन्दी":{ + search:"खोज", + gptPlaceHolder:"मूवी अनुशंसाओं के रूप में GPT का उपयोग करें ...", + }, +} + +export default language; \ No newline at end of file diff --git a/src/utils/openAI.js b/src/utils/openAI.js new file mode 100644 index 0000000..0e45b15 --- /dev/null +++ b/src/utils/openAI.js @@ -0,0 +1,11 @@ +// import OpenAI from 'openai'; +// import { OPEN_AI_KEY } from './constant'; + + +// const openai = new OpenAI({ +// apiKey: OPEN_AI_KEY , +// dangerouslyAllowBrowser: true, +// // This is the default and can be omitted +// }); + +// export default openai; \ No newline at end of file