diff --git a/movie-search/src/components/pagination.tsx b/Pagination.tsx similarity index 93% rename from movie-search/src/components/pagination.tsx rename to Pagination.tsx index 18ac113..cd54fbb 100644 --- a/movie-search/src/components/pagination.tsx +++ b/Pagination.tsx @@ -1,6 +1,5 @@ import { ReactEventHandler, useState } from "react"; - -export default ({ pages, onPageChange, currentPage }: any) => { +export default function Pagination({ pages, onPageChange, currentPage }: any) { const [page, setPage] = useState(currentPage); const handleClick = (e: any) => { const { value } = e.target; @@ -62,4 +61,4 @@ export default ({ pages, onPageChange, currentPage }: any) => { >"} /> ); -}; +} diff --git a/movie-search/__tests__/MovieCard.test.jsx b/movie-search/__tests__/MovieCard.test.jsx index c91c8f2..07c43eb 100644 --- a/movie-search/__tests__/MovieCard.test.jsx +++ b/movie-search/__tests__/MovieCard.test.jsx @@ -1,6 +1,6 @@ import "@testing-library/jest-dom"; import {render, screen} from '@testing-library/react' -import MovieCard from '../src/app/Search/MovieCard.tsx' +import MovieCard from '../src/common/components/MovieCard.tsx' const movie = { Title: "Dune", Year: "2000", diff --git a/movie-search/__tests__/omdb.test.jsx b/movie-search/__tests__/omdb.test.jsx index 8054a7c..d74f27c 100644 --- a/movie-search/__tests__/omdb.test.jsx +++ b/movie-search/__tests__/omdb.test.jsx @@ -1,8 +1,19 @@ import "@testing-library/jest-dom"; import { queryOMDb } from "../src/api/omdb.ts"; -test("queryOMDb returns movie data", async () => { +test("queryOMDb returns movie data successfully", async () => { const data = await queryOMDb("s=back to"); - - expect(data).toHaveProperty("Response"); + + expect(data).toHaveProperty("Response", "True"); }); + +test("queryOMDb returns movie with error", async () => { + const data = await queryOMDb("f=dune"); + + expect(data).toHaveProperty("Response", "False"); +}); + +// f=dune + +// Warning: React does not recognize the `fetchPriority` prop on a DOM element +// The `punycode` module is deprecated. Please use a userland alternative instead. \ No newline at end of file diff --git a/movie-search/package-lock.json b/movie-search/package-lock.json index e100e6b..163e02a 100644 --- a/movie-search/package-lock.json +++ b/movie-search/package-lock.json @@ -10,18 +10,19 @@ "dependencies": { "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", "framer-motion": "^11.2.6", - "next": "14.2.3", + "next": "^14.2.3", "react": "^18", "react-dom": "^18", "ts-node-dev": "^2.0.0" }, "devDependencies": { + "@babel/preset-typescript": "^7.24.6", "@testing-library/jest-dom": "^6.4.5", "@testing-library/react": "^15.0.7", "@types/node": "^20", - "@types/react": "^18", - "@types/react-dom": "^18", "autoprefixer": "^10.4.19", "eslint": "^8", "eslint-config-next": "14.2.3", @@ -157,6 +158,18 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.6.tgz", + "integrity": "sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-compilation-targets": { "version": "7.24.6", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.6.tgz", @@ -191,6 +204,38 @@ "semver": "bin/semver.js" } }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.6.tgz", + "integrity": "sha512-djsosdPJVZE6Vsw3kk7IPRWethP94WHGOhQTc67SNXE0ZzMhHgALw8iGmYS0TD1bbMM0VDROy43od7/hN6WYcA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.6", + "@babel/helper-environment-visitor": "^7.24.6", + "@babel/helper-function-name": "^7.24.6", + "@babel/helper-member-expression-to-functions": "^7.24.6", + "@babel/helper-optimise-call-expression": "^7.24.6", + "@babel/helper-replace-supers": "^7.24.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.6", + "@babel/helper-split-export-declaration": "^7.24.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/helper-environment-visitor": { "version": "7.24.6", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.6.tgz", @@ -225,6 +270,18 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.6.tgz", + "integrity": "sha512-OTsCufZTxDUsv2/eDXanw/mUZHWOxSbEmC3pP8cgjcy5rgeVPWWMStnv274DV60JtHxTk0adT0QrCzC4M9NWGg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-module-imports": { "version": "7.24.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.6.tgz", @@ -255,6 +312,18 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.6.tgz", + "integrity": "sha512-3SFDJRbx7KuPRl8XDUr8O7GAEB8iGyWPjLKJh/ywP/Iy9WOmEfMrsWbaZpvBu2HSYn4KQygIsz0O7m8y10ncMA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-plugin-utils": { "version": "7.24.6", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.6.tgz", @@ -264,6 +333,23 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.6.tgz", + "integrity": "sha512-mRhfPwDqDpba8o1F8ESxsEkJMQkUF8ZIWrAc0FtWhxnjfextxMWxr22RtFizxxSYLjVHDeMgVsRq8BBZR2ikJQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.6", + "@babel/helper-member-expression-to-functions": "^7.24.6", + "@babel/helper-optimise-call-expression": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/helper-simple-access": { "version": "7.24.6", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.6.tgz", @@ -276,6 +362,18 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.6.tgz", + "integrity": "sha512-jhbbkK3IUKc4T43WadP96a27oYti9gEf1LdyGSP2rHGH77kwLwfhO7TgwnWvxxQVmke0ImmCSS47vcuxEMGD3Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-split-export-declaration": { "version": "7.24.6", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.6.tgz", @@ -593,6 +691,60 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.6.tgz", + "integrity": "sha512-JEV8l3MHdmmdb7S7Cmx6rbNEjRCgTQMZxllveHO0mx6uiclB0NflCawlQQ6+o5ZrwjUBYPzHm2XoK4wqGVUFuw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-simple-access": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.6.tgz", + "integrity": "sha512-H0i+hDLmaYYSt6KU9cZE0gb3Cbssa/oxWis7PX4ofQzbvsfix9Lbh8SRk7LCPDlLWJHUiFeHU0qRRpF/4Zv7mQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.6", + "@babel/helper-create-class-features-plugin": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/plugin-syntax-typescript": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.24.6.tgz", + "integrity": "sha512-U10aHPDnokCFRXgyT/MaIRTivUu2K/mu0vJlwRS9LxJmJet+PFQNKpggPyFCUtC6zWSBPjvxjnpNkAn3Uw2m5w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-validator-option": "^7.24.6", + "@babel/plugin-syntax-jsx": "^7.24.6", + "@babel/plugin-transform-modules-commonjs": "^7.24.6", + "@babel/plugin-transform-typescript": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/runtime": { "version": "7.24.5", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz", @@ -1930,14 +2082,12 @@ "node_modules/@types/prop-types": { "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", - "dev": true + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" }, "node_modules/@types/react": { - "version": "18.3.2", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.2.tgz", - "integrity": "sha512-Btgg89dAnqD4vV7R3hlwOxgqobUQKgx3MmrQRi0yYbs/P0ym8XozIAlkqVilPqHQwXs4e9Tf63rrCgl58BcO4w==", - "dev": true, + "version": "18.3.3", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", + "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -1947,7 +2097,6 @@ "version": "18.3.0", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", - "dev": true, "dependencies": { "@types/react": "*" } @@ -9473,6 +9622,15 @@ "jsesc": "^2.5.1" } }, + "@babel/helper-annotate-as-pure": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.6.tgz", + "integrity": "sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==", + "dev": true, + "requires": { + "@babel/types": "^7.24.6" + } + }, "@babel/helper-compilation-targets": { "version": "7.24.6", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.6.tgz", @@ -9503,6 +9661,31 @@ } } }, + "@babel/helper-create-class-features-plugin": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.6.tgz", + "integrity": "sha512-djsosdPJVZE6Vsw3kk7IPRWethP94WHGOhQTc67SNXE0ZzMhHgALw8iGmYS0TD1bbMM0VDROy43od7/hN6WYcA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.24.6", + "@babel/helper-environment-visitor": "^7.24.6", + "@babel/helper-function-name": "^7.24.6", + "@babel/helper-member-expression-to-functions": "^7.24.6", + "@babel/helper-optimise-call-expression": "^7.24.6", + "@babel/helper-replace-supers": "^7.24.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.6", + "@babel/helper-split-export-declaration": "^7.24.6", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, "@babel/helper-environment-visitor": { "version": "7.24.6", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.6.tgz", @@ -9528,6 +9711,15 @@ "@babel/types": "^7.24.6" } }, + "@babel/helper-member-expression-to-functions": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.6.tgz", + "integrity": "sha512-OTsCufZTxDUsv2/eDXanw/mUZHWOxSbEmC3pP8cgjcy5rgeVPWWMStnv274DV60JtHxTk0adT0QrCzC4M9NWGg==", + "dev": true, + "requires": { + "@babel/types": "^7.24.6" + } + }, "@babel/helper-module-imports": { "version": "7.24.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.6.tgz", @@ -9549,12 +9741,32 @@ "@babel/helper-validator-identifier": "^7.24.6" } }, + "@babel/helper-optimise-call-expression": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.6.tgz", + "integrity": "sha512-3SFDJRbx7KuPRl8XDUr8O7GAEB8iGyWPjLKJh/ywP/Iy9WOmEfMrsWbaZpvBu2HSYn4KQygIsz0O7m8y10ncMA==", + "dev": true, + "requires": { + "@babel/types": "^7.24.6" + } + }, "@babel/helper-plugin-utils": { "version": "7.24.6", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.6.tgz", "integrity": "sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg==", "dev": true }, + "@babel/helper-replace-supers": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.6.tgz", + "integrity": "sha512-mRhfPwDqDpba8o1F8ESxsEkJMQkUF8ZIWrAc0FtWhxnjfextxMWxr22RtFizxxSYLjVHDeMgVsRq8BBZR2ikJQ==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.24.6", + "@babel/helper-member-expression-to-functions": "^7.24.6", + "@babel/helper-optimise-call-expression": "^7.24.6" + } + }, "@babel/helper-simple-access": { "version": "7.24.6", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.6.tgz", @@ -9564,6 +9776,15 @@ "@babel/types": "^7.24.6" } }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.6.tgz", + "integrity": "sha512-jhbbkK3IUKc4T43WadP96a27oYti9gEf1LdyGSP2rHGH77kwLwfhO7TgwnWvxxQVmke0ImmCSS47vcuxEMGD3Q==", + "dev": true, + "requires": { + "@babel/types": "^7.24.6" + } + }, "@babel/helper-split-export-declaration": { "version": "7.24.6", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.6.tgz", @@ -9793,6 +10014,42 @@ "@babel/helper-plugin-utils": "^7.24.6" } }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.6.tgz", + "integrity": "sha512-JEV8l3MHdmmdb7S7Cmx6rbNEjRCgTQMZxllveHO0mx6uiclB0NflCawlQQ6+o5ZrwjUBYPzHm2XoK4wqGVUFuw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-simple-access": "^7.24.6" + } + }, + "@babel/plugin-transform-typescript": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.6.tgz", + "integrity": "sha512-H0i+hDLmaYYSt6KU9cZE0gb3Cbssa/oxWis7PX4ofQzbvsfix9Lbh8SRk7LCPDlLWJHUiFeHU0qRRpF/4Zv7mQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.24.6", + "@babel/helper-create-class-features-plugin": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/plugin-syntax-typescript": "^7.24.6" + } + }, + "@babel/preset-typescript": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.24.6.tgz", + "integrity": "sha512-U10aHPDnokCFRXgyT/MaIRTivUu2K/mu0vJlwRS9LxJmJet+PFQNKpggPyFCUtC6zWSBPjvxjnpNkAn3Uw2m5w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-validator-option": "^7.24.6", + "@babel/plugin-syntax-jsx": "^7.24.6", + "@babel/plugin-transform-modules-commonjs": "^7.24.6", + "@babel/plugin-transform-typescript": "^7.24.6" + } + }, "@babel/runtime": { "version": "7.24.5", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz", @@ -10815,14 +11072,12 @@ "@types/prop-types": { "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", - "dev": true + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" }, "@types/react": { - "version": "18.3.2", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.2.tgz", - "integrity": "sha512-Btgg89dAnqD4vV7R3hlwOxgqobUQKgx3MmrQRi0yYbs/P0ym8XozIAlkqVilPqHQwXs4e9Tf63rrCgl58BcO4w==", - "dev": true, + "version": "18.3.3", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", + "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", "requires": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -10832,7 +11087,6 @@ "version": "18.3.0", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", - "dev": true, "requires": { "@types/react": "*" } diff --git a/movie-search/package.json b/movie-search/package.json index 55edbf9..e30a84f 100644 --- a/movie-search/package.json +++ b/movie-search/package.json @@ -13,18 +13,19 @@ "dependencies": { "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", "framer-motion": "^11.2.6", - "next": "14.2.3", + "next": "^14.2.3", "react": "^18", "react-dom": "^18", "ts-node-dev": "^2.0.0" }, "devDependencies": { + "@babel/preset-typescript": "^7.24.6", "@testing-library/jest-dom": "^6.4.5", "@testing-library/react": "^15.0.7", "@types/node": "^20", - "@types/react": "^18", - "@types/react-dom": "^18", "autoprefixer": "^10.4.19", "eslint": "^8", "eslint-config-next": "14.2.3", diff --git a/movie-search/src/api/omdb.ts b/movie-search/src/api/omdb.ts index 4b83eae..487fbc3 100644 --- a/movie-search/src/api/omdb.ts +++ b/movie-search/src/api/omdb.ts @@ -3,6 +3,8 @@ const url = `${process.env.OMDB_URL}?apikey=${process.env.API_KEY}`; export const queryOMDb = async (queryParamString: string) => { "use server"; try { + // await new Promise((resolve) => setTimeout(resolve, 2000)); + const queryUrl = `${url}&${queryParamString}`; const response = await fetch(queryUrl); if (!response.ok) { diff --git a/movie-search/src/app/Favorites/favoriteList.tsx b/movie-search/src/app/Favorites/favoriteList.tsx index 9268b58..48cad13 100644 --- a/movie-search/src/app/Favorites/favoriteList.tsx +++ b/movie-search/src/app/Favorites/favoriteList.tsx @@ -1,15 +1,12 @@ -'use client' +"use client"; -import { FavoriteContext } from "@/components/FavoriteContext"; +import { FavoriteContext } from "@/common/components/FavoriteContext"; +import MovieList from "@/common/components/MovieList"; import { useContext } from "react"; -export default () => { - const {favorites} = useContext(FavoriteContext) +export default function FavoriteList() { + const { favorites } = useContext(FavoriteContext); return ( - + ); -}; +} diff --git a/movie-search/src/app/Favorites/page.tsx b/movie-search/src/app/Favorites/page.tsx index 20b4f85..b146d5e 100644 --- a/movie-search/src/app/Favorites/page.tsx +++ b/movie-search/src/app/Favorites/page.tsx @@ -1,6 +1,6 @@ import FavoriteList from "./favoriteList"; -export default () => { +export default function Favorites() { return (

Your Favorites!

diff --git a/movie-search/src/app/Movie/loading.tsx b/movie-search/src/app/Movie/loading.tsx new file mode 100644 index 0000000..ba73539 --- /dev/null +++ b/movie-search/src/app/Movie/loading.tsx @@ -0,0 +1,5 @@ +import Loading from "@/common/components/Loading"; + +export default function loading() { + return ; +} diff --git a/movie-search/src/app/Movie/page.tsx b/movie-search/src/app/Movie/page.tsx index e9565ec..b664216 100644 --- a/movie-search/src/app/Movie/page.tsx +++ b/movie-search/src/app/Movie/page.tsx @@ -1,21 +1,22 @@ import { queryOMDb } from "@/api/omdb"; -import { INextJsProps, stringifyQueryParams } from "../Search/page"; -import ImgCard from "@/components/ImgCard"; +import { INextJsProps } from "../Search/page"; +import ImgCard from "@/common/components/ImgCard"; +import { stringifyQueryParams } from "@/common/utils/searchParams"; -export default async ({ searchParams }: INextJsProps) => { +export default async function Movie({ searchParams }: INextJsProps) { const movie = await queryOMDb(stringifyQueryParams(searchParams!)); - const { Poster, Ratings, ...rest } = movie; + const { Poster, Title, Ratings, ...details } = movie; return ( -
+
-

{movie.Title}

- {Object.entries(rest).map(([key, value]) => { +

{Title}

+ {Object.entries(details).map(([key, value]) => { return (

{key}: @@ -25,7 +26,7 @@ export default async ({ searchParams }: INextJsProps) => { })}

Ratings:

    - {movie.Ratings.map((r: { Source: string; Value: string }) => ( + {Ratings.map((r: { Source: string; Value: string }) => (
  • {r.Source} - {r.Value}
  • @@ -35,4 +36,4 @@ export default async ({ searchParams }: INextJsProps) => {
); -}; +} diff --git a/movie-search/src/app/Search/MovieCard.tsx b/movie-search/src/app/Search/MovieCard.tsx deleted file mode 100644 index 8ad27b9..0000000 --- a/movie-search/src/app/Search/MovieCard.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import FavoriteBtn from "@/components/FavoriteBtn"; -import ImgCard from "@/components/ImgCard"; -import Link from "next/link"; - -export interface IMovieCardItem { - Title: string; - Year: string; - imdbID: string; - Type: string; - Poster: string; -} -interface IMovieCardProps { - movie: IMovieCardItem; -} - -export default ({ movie }: IMovieCardProps) => { - return ( - -
-

{movie.Title}

-

Circa: {movie.Year}

-
-
- - Movie Details - - -
-
- ); -}; diff --git a/movie-search/src/app/Search/MovieList.tsx b/movie-search/src/app/Search/MovieList.tsx deleted file mode 100644 index 1d73f64..0000000 --- a/movie-search/src/app/Search/MovieList.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import MovieCard, { IMovieCardItem } from "./MovieCard"; - -interface IMovieListProps { - movies: Array; -} - -export default ({ movies }: IMovieListProps) => { - return ( -
-
- {movies.map((m) => ( -
- -
- ))} -
-
- ); -}; diff --git a/movie-search/src/app/Search/SearchBar.tsx b/movie-search/src/app/Search/SearchBar.tsx index 303a753..ebd337c 100644 --- a/movie-search/src/app/Search/SearchBar.tsx +++ b/movie-search/src/app/Search/SearchBar.tsx @@ -1,20 +1,24 @@ +import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; -export default () => { +export default function SearchBar() { const searchMovies = async (formData: FormData) => { "use server"; const movieTitle = formData.get("movieTitle"); + // revalidatePath('/Search') redirect(`/Search?s=${movieTitle}`); }; return ( -
- -
+ +
+ +
+
); -}; +} diff --git a/movie-search/src/app/Search/SearchPage.tsx b/movie-search/src/app/Search/SearchPage.tsx new file mode 100644 index 0000000..70c4b71 --- /dev/null +++ b/movie-search/src/app/Search/SearchPage.tsx @@ -0,0 +1,16 @@ +import { queryOMDb } from "@/api/omdb"; +import MovieList from "../../common/components/MovieList"; + +export default async function SearchPage({ + queryParamString, +}: { + queryParamString: string; +}) { + + const { Search } = await queryOMDb(queryParamString); + const movies = Search || []; + + return ( + + ); +} diff --git a/movie-search/src/app/Search/page.tsx b/movie-search/src/app/Search/page.tsx index 42caf90..fab1fb2 100644 --- a/movie-search/src/app/Search/page.tsx +++ b/movie-search/src/app/Search/page.tsx @@ -1,29 +1,22 @@ -import { queryOMDb } from "@/api/omdb"; -import MovieList from "./MovieList"; +import { stringifyQueryParams } from "@/common/utils/searchParams"; +import { Suspense } from "react"; +import SearchPage from "./SearchPage"; import SearchBar from "./SearchBar"; +import Loading from "@/common/components/Loading"; export interface INextJsProps { searchParams?: object; } -export const stringifyQueryParams = (searchParams: object) => - Object.entries(searchParams) - .map( - ([key, value], i, arr) => - `${key}=${value}${i < arr.length - 1 ? "&" : ""}` - ) - .toString(); - -export default async ({ searchParams }: INextJsProps) => { +export default async function Search({ searchParams }: INextJsProps) { const queryParamString = stringifyQueryParams(searchParams!); - // console.log(queryParamString) - const { Search } = await queryOMDb(queryParamString); - const movies = Search || []; return (
- + }> + +
); -}; +} diff --git a/movie-search/src/app/globals.css b/movie-search/src/app/globals.css index 371ce7a..d526588 100644 --- a/movie-search/src/app/globals.css +++ b/movie-search/src/app/globals.css @@ -51,12 +51,12 @@ --background-start-rgb: 0, 0, 0; --background-end-rgb: 0, 0, 0; - --primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0)); + --primary-glow: radial-gradient(rgba(210, 1, 255, 0.5), rgba(1, 65, 255, 0)); --secondary-glow: linear-gradient( to bottom right, rgba(1, 65, 255, 0), rgba(1, 65, 255, 0), - rgba(1, 65, 255, 0.3) + rgba(180, 1, 255, 0.3) ); --tile-start-rgb: 2, 13, 46; @@ -92,6 +92,7 @@ body { body { color: rgb(var(--foreground-rgb)); + /* background: #2bff0110 */ background: linear-gradient( to bottom, transparent, diff --git a/movie-search/src/app/layout.tsx b/movie-search/src/app/layout.tsx index 7773a94..d483bea 100644 --- a/movie-search/src/app/layout.tsx +++ b/movie-search/src/app/layout.tsx @@ -1,14 +1,14 @@ import type { Metadata } from "next"; import { Inter } from "next/font/google"; import "./globals.css"; -import NavBar from "@/components/navBar"; -import { FavoriteProvider } from "@/components/FavoriteContext"; +import NavBar from "@/common/components/NavBar"; +import { FavoriteProvider } from "@/common/components/FavoriteContext"; const inter = Inter({ subsets: ["latin"] }); export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "Movie Search App", + description: "Powered by Nextjs and OMDb.", }; export default function RootLayout({ @@ -17,8 +17,8 @@ export default function RootLayout({ children: React.ReactNode; }>) { return ( - - + + {children} diff --git a/movie-search/src/common/classes.ts b/movie-search/src/common/classes.ts new file mode 100644 index 0000000..dce70ee --- /dev/null +++ b/movie-search/src/common/classes.ts @@ -0,0 +1 @@ +const responsiveContainer = '' \ No newline at end of file diff --git a/movie-search/src/common/components/FavoriteBtn.tsx b/movie-search/src/common/components/FavoriteBtn.tsx new file mode 100644 index 0000000..34002f0 --- /dev/null +++ b/movie-search/src/common/components/FavoriteBtn.tsx @@ -0,0 +1,29 @@ +"use client"; + +import { useContext } from "react"; +import { FavoriteContext } from "./FavoriteContext"; + +export default function FavoriteBtn({ movie }: any) { + const { favorites, setFavorites } = useContext(FavoriteContext); + const filteredFavorites = favorites.filter((f) => f.imdbID != movie.imdbID); + const isFavorite = + favorites.filter((f) => f.imdbID == movie.imdbID).length == 1; + + return ( + + ); +} diff --git a/movie-search/src/components/FavoriteContext.tsx b/movie-search/src/common/components/FavoriteContext.tsx similarity index 92% rename from movie-search/src/components/FavoriteContext.tsx rename to movie-search/src/common/components/FavoriteContext.tsx index a22e26c..37d1b68 100644 --- a/movie-search/src/components/FavoriteContext.tsx +++ b/movie-search/src/common/components/FavoriteContext.tsx @@ -1,6 +1,7 @@ 'use client' -import { IMovieCardItem } from "@/app/Search/MovieCard"; + import { PropsWithChildren, createContext, useState } from "react"; +import { IMovieCardItem } from "./MovieCard"; interface IFavoriteContext { favorites: Array diff --git a/movie-search/src/components/ImgCard.tsx b/movie-search/src/common/components/ImgCard.tsx similarity index 90% rename from movie-search/src/components/ImgCard.tsx rename to movie-search/src/common/components/ImgCard.tsx index d5282d7..79d0c9c 100644 --- a/movie-search/src/components/ImgCard.tsx +++ b/movie-search/src/common/components/ImgCard.tsx @@ -7,19 +7,18 @@ interface ICardProps extends PropsWithChildren { alt: string; classNames?: string; } -export default ({ +export default function ImgCard({ classNames, width, height, src, alt, children, -}: ICardProps) => { +}: ICardProps) { return (
+

+ Loading... +

+
+ ); +} diff --git a/movie-search/src/common/components/MovieCard.tsx b/movie-search/src/common/components/MovieCard.tsx new file mode 100644 index 0000000..245263d --- /dev/null +++ b/movie-search/src/common/components/MovieCard.tsx @@ -0,0 +1,41 @@ +import FavoriteBtn from "@/common/components/FavoriteBtn"; +import ImgCard from "@/common/components/ImgCard"; +import Link from "next/link"; + +export interface IMovieCardItem { + Title: string; + Year: string; + imdbID: string; + Type: string; + Poster: string; +} +interface IMovieCardProps { + movie: IMovieCardItem; +} + +export default function MovieCard({ movie }: IMovieCardProps) { + return ( + +
+

{movie.Title}

+

Circa: {movie.Year}

+ +
+ + Movie Details + + +
+
+
+ ); +} diff --git a/movie-search/src/common/components/MovieList.tsx b/movie-search/src/common/components/MovieList.tsx new file mode 100644 index 0000000..c002f12 --- /dev/null +++ b/movie-search/src/common/components/MovieList.tsx @@ -0,0 +1,25 @@ +import MovieCard, { IMovieCardItem } from "./MovieCard"; + +export interface IMovieListProps { + movies: Array; +} + +export default function MovieList({ movies }: IMovieListProps) { + return ( +
+
+ {movies.length > 0 ? ( + movies.map((m) => ( +
+ +
+ )) + ) : ( +

Nothing to show

+ )} +
+
+ ); +} diff --git a/movie-search/src/components/navBar.tsx b/movie-search/src/common/components/NavBar.tsx similarity index 65% rename from movie-search/src/components/navBar.tsx rename to movie-search/src/common/components/NavBar.tsx index 8d4ec2a..13c9a36 100644 --- a/movie-search/src/components/navBar.tsx +++ b/movie-search/src/common/components/NavBar.tsx @@ -1,8 +1,8 @@ import Link from "next/link"; -export default () => { +export default function NavBar() { return ( -