diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..accf79e327469c30c9457a0b38cc1c9df1046c48
Binary files /dev/null and b/.DS_Store differ
diff --git a/movie-group-8/.env b/movie-group-8/.env
index e847065da5446d61fa32a810397b21b7383e4cb1..4ec34fde83f0116c4ff586e6f695eb0a151ad951 100644
--- a/movie-group-8/.env
+++ b/movie-group-8/.env
@@ -1 +1,3 @@
 VITE_TMDB_API_KEY=42259df77843511296d8096fa29e08a8
+
+VITE_TMDB_BASE=https://api.themoviedb.org/3
diff --git a/movie-group-8/package-lock.json b/movie-group-8/package-lock.json
index 776cb26126436ac733829e82ef1a9429176c4a92..9c88ee0b1d6c8e4d01f7eb84321d22531a6eca11 100644
--- a/movie-group-8/package-lock.json
+++ b/movie-group-8/package-lock.json
@@ -11,6 +11,7 @@
         "@headlessui/vue": "^1.7.23",
         "@heroicons/vue": "^2.2.0",
         "@tailwindcss/vite": "^4.0.14",
+        "axios": "^1.9.0",
         "firebase": "^11.4.0",
         "movie-group-8": "file:",
         "tailwindcss": "^4.0.14",
@@ -1719,6 +1720,36 @@
         "url": "https://github.com/chalk/ansi-styles?sponsor=1"
       }
     },
+    "node_modules/asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+      "license": "MIT"
+    },
+    "node_modules/axios": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz",
+      "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==",
+      "license": "MIT",
+      "dependencies": {
+        "follow-redirects": "^1.15.6",
+        "form-data": "^4.0.0",
+        "proxy-from-env": "^1.1.0"
+      }
+    },
+    "node_modules/call-bind-apply-helpers": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+      "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
     "node_modules/cliui": {
       "version": "8.0.1",
       "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
@@ -1748,11 +1779,32 @@
       "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
       "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
     },
+    "node_modules/combined-stream": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "license": "MIT",
+      "dependencies": {
+        "delayed-stream": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/csstype": {
       "version": "3.1.3",
       "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
       "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
     },
+    "node_modules/delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
     "node_modules/detect-libc": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
@@ -1761,6 +1813,20 @@
         "node": ">=8"
       }
     },
+    "node_modules/dunder-proto": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+      "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.1",
+        "es-errors": "^1.3.0",
+        "gopd": "^1.2.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
     "node_modules/emoji-regex": {
       "version": "8.0.0",
       "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -1789,6 +1855,51 @@
         "url": "https://github.com/fb55/entities?sponsor=1"
       }
     },
+    "node_modules/es-define-property": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+      "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-errors": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+      "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-object-atoms": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+      "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-set-tostringtag": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
+      "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.6",
+        "has-tostringtag": "^1.0.2",
+        "hasown": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
     "node_modules/esbuild": {
       "version": "0.25.1",
       "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz",
@@ -1901,6 +2012,41 @@
         "@firebase/vertexai": "1.1.0"
       }
     },
+    "node_modules/follow-redirects": {
+      "version": "1.15.9",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
+      "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/RubenVerborgh"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=4.0"
+      },
+      "peerDependenciesMeta": {
+        "debug": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/form-data": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
+      "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
+      "license": "MIT",
+      "dependencies": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.8",
+        "es-set-tostringtag": "^2.1.0",
+        "mime-types": "^2.1.12"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
     "node_modules/fsevents": {
       "version": "2.3.3",
       "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@@ -1914,6 +2060,15 @@
         "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
       }
     },
+    "node_modules/function-bind": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/get-caller-file": {
       "version": "2.0.5",
       "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
@@ -1922,11 +2077,99 @@
         "node": "6.* || 8.* || >= 10.*"
       }
     },
+    "node_modules/get-intrinsic": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+      "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.2",
+        "es-define-property": "^1.0.1",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.1.1",
+        "function-bind": "^1.1.2",
+        "get-proto": "^1.0.1",
+        "gopd": "^1.2.0",
+        "has-symbols": "^1.1.0",
+        "hasown": "^2.0.2",
+        "math-intrinsics": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/get-proto": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+      "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+      "license": "MIT",
+      "dependencies": {
+        "dunder-proto": "^1.0.1",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/gopd": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+      "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/graceful-fs": {
       "version": "4.2.11",
       "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
       "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
     },
+    "node_modules/has-symbols": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+      "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-tostringtag": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+      "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+      "license": "MIT",
+      "dependencies": {
+        "has-symbols": "^1.0.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/hasown": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+      "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+      "license": "MIT",
+      "dependencies": {
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
     "node_modules/http-parser-js": {
       "version": "0.5.9",
       "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.9.tgz",
@@ -2188,6 +2431,36 @@
         "@jridgewell/sourcemap-codec": "^1.5.0"
       }
     },
+    "node_modules/math-intrinsics": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+      "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/mime-db": {
+      "version": "1.52.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mime-types": {
+      "version": "2.1.35",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+      "license": "MIT",
+      "dependencies": {
+        "mime-db": "1.52.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
     "node_modules/movie-group-8": {
       "resolved": "",
       "link": true
@@ -2276,6 +2549,12 @@
         "node": ">=12.0.0"
       }
     },
+    "node_modules/proxy-from-env": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+      "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+      "license": "MIT"
+    },
     "node_modules/require-directory": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@@ -2412,9 +2691,9 @@
       "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="
     },
     "node_modules/vite": {
-      "version": "6.3.4",
-      "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.4.tgz",
-      "integrity": "sha512-BiReIiMS2fyFqbqNT/Qqt4CVITDU9M9vE+DKcVAsB+ZV0wvTKd+3hMbkpxz1b+NmEDMegpVbisKiAZOnvO92Sw==",
+      "version": "6.3.3",
+      "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.3.tgz",
+      "integrity": "sha512-5nXH+QsELbFKhsEfWLkHrvgRpTdGJzqOZ+utSdmPTvwHmvU6ITTm3xx+mRusihkcI8GeC7lCDyn3kDtiki9scw==",
       "license": "MIT",
       "dependencies": {
         "esbuild": "^0.25.0",
diff --git a/movie-group-8/package.json b/movie-group-8/package.json
index 490d97713be8921292573244ccacae56fe3c8d84..22af383cd1cebd8a1c2023b2f9e7938c34cbac5d 100644
--- a/movie-group-8/package.json
+++ b/movie-group-8/package.json
@@ -12,6 +12,7 @@
     "@headlessui/vue": "^1.7.23",
     "@heroicons/vue": "^2.2.0",
     "@tailwindcss/vite": "^4.0.14",
+    "axios": "^1.9.0",
     "firebase": "^11.4.0",
     "movie-group-8": "file:",
     "tailwindcss": "^4.0.14",
diff --git a/movie-group-8/src/App.vue b/movie-group-8/src/App.vue
index cc3a63d6cb3cd5e2c6fb51c3e4617a07cf48e9bf..06a35b97d34a73ade52d72d75981b01ddec76847 100644
--- a/movie-group-8/src/App.vue
+++ b/movie-group-8/src/App.vue
@@ -12,3 +12,5 @@ import Navbar from './components/Navbar.vue';
 
 <style scoped>
 </style>
+
+
diff --git a/movie-group-8/src/components/MovieList.vue b/movie-group-8/src/components/MovieList.vue
new file mode 100644
index 0000000000000000000000000000000000000000..aff845ac398f5703e6e5caf3eb56c0ffabfcb08b
--- /dev/null
+++ b/movie-group-8/src/components/MovieList.vue
@@ -0,0 +1,120 @@
+<template>
+  <div class="movie-list">
+    <div v-if="!movies.length" class="no-results">
+      <slot name="empty">No movies found.</slot>
+    </div>
+    <ul v-else class="movies">
+      <li v-for="movie in movies" :key="movie.id" class="movie-item">
+        <router-link
+            :to="{ name: 'FilmDetails', params: { id: movie.id } }"
+            class="movie-link"
+        >
+            <img
+            v-if="movie.poster_path"
+            :src="getPosterUrl(movie.poster_path)"
+            :alt="`${movie.title} poster`"
+            class="poster"
+            />
+            <div class="details">
+            <h2 class="title">{{ movie.title }}</h2>
+            <p class="release-date">{{ formatDate(movie.release_date) }}</p>
+            <p class="overview">{{ movie.overview || 'No overview available.' }}</p>
+            </div>
+        </router-link>
+
+      </li>
+    </ul>
+  </div>
+</template>
+
+<script setup>
+import { defineProps } from 'vue'
+
+const props = defineProps({
+  movies: {
+    type: Array,
+    required: true
+  }
+})
+
+// TMDB image base URL from Vite env or fallback
+const IMAGE_BASE = import.meta.env.VITE_TMDB_IMAGE_BASE || 'https://image.tmdb.org/t/p/w200'
+
+/**
+ * Build full poster URL
+ */
+function getPosterUrl(path) {
+  return `${IMAGE_BASE}${path}`
+}
+
+/**
+ * Format a date string to a more readable form
+ */
+function formatDate(dateString) {
+  if (!dateString) return 'Unknown'
+  const options = { year: 'numeric', month: 'long', day: 'numeric' }
+  return new Date(dateString).toLocaleDateString(undefined, options)
+}
+</script>
+
+<style scoped>
+.movie-list {
+  display: flex;
+  flex-direction: column;
+}
+
+.no-results {
+  text-align: center;
+  color: #666;
+  font-style: italic;
+}
+
+.movies {
+  list-style: none;
+  padding: 0;
+  display: grid;
+  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
+  gap: 1rem;
+}
+
+.movie-item {
+  background: #fff;
+  border-radius: 8px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+  overflow: hidden;
+  display: flex;
+  flex-direction: column;
+}
+
+.poster {
+  width: 100%;
+  object-fit: cover;
+  aspect-ratio: 2 / 3;
+}
+
+.details {
+  padding: 0.75rem;
+  display: flex;
+  flex-direction: column;
+  flex-grow: 1;
+}
+
+.title {
+  font-size: 1.1rem;
+  margin: 0 0 0.5rem;
+}
+
+.release-date {
+  font-size: 0.875rem;
+  color: #888;
+  margin: 0 0 0.5rem;
+}
+
+.overview {
+  font-size: 0.9rem;
+  color: #444;
+  flex-grow: 1;
+}
+
+
+</style>
diff --git a/movie-group-8/src/composables/useMovies,js b/movie-group-8/src/composables/useMovies,js
new file mode 100644
index 0000000000000000000000000000000000000000..673d1e96b8d09008d2879a81c74758a1d19ac4a8
--- /dev/null
+++ b/movie-group-8/src/composables/useMovies,js
@@ -0,0 +1,29 @@
+import axios from 'axios'
+import { ref } from 'vue'
+
+const API_KEY = process.env.VITE_TMDB_API_KEY
+const BASE   = process.env.VUE_APP_TMDB_BASE
+
+export function useMovies() {
+  const results = ref([])
+  const loading = ref(false)
+  const error   = ref(null)
+
+  async function search(query) {
+    loading.value = true
+    error.value   = null
+    try {
+      const url = `${BASE}/search/movie`
+      const { data } = await axios.get(url, {
+        params: { api_key: API_KEY, query }
+      })
+      results.value = data.results
+    } catch (e) {
+      error.value = e
+    } finally {
+      loading.value = false
+    }
+  }
+
+  return { results, loading, error, search }
+}
\ No newline at end of file
diff --git a/movie-group-8/src/router/index.js b/movie-group-8/src/router/index.js
index b8f7ba088c1142865c0ffda0982f458c8f7f6c5b..a989d41f6c061f29bff582b1251572f898fc31fe 100644
--- a/movie-group-8/src/router/index.js
+++ b/movie-group-8/src/router/index.js
@@ -1,7 +1,7 @@
 import { getAuth, onAuthStateChanged } from 'firebase/auth';
 import { createRouter, createWebHistory } from 'vue-router';
-
-
+import Films from '@/views/Films.vue'
+import FilmDetails from '@/views/FilmDetails.vue'
 
 const router = createRouter({
     history: createWebHistory(),
@@ -13,11 +13,18 @@ const router = createRouter({
         { path: '/register', component: () => import('../views/Register.vue') },
         { path: '/login', component: () => import('../views/Login.vue') },
         { path: '/recover-account', component: () => import('../views/RecoverAccount.vue') },
-        { 
-          path: '/films', 
-          component: () => import('../views/Films.vue'), 
-          meta: { requiresAuth: true },
+        {
+            path: '/films',
+            name: 'Films',
+            component: Films,
+            meta: { requiresAuth: true }  
         },
+        {
+            path: '/films/:id',
+            name: 'FilmDetails',
+            component: FilmDetails,
+        },
+
         { 
             path: '/watchlist', 
             component: () => import('../views/Watchlist.vue'), 
diff --git a/movie-group-8/src/views/FilmDetails.vue b/movie-group-8/src/views/FilmDetails.vue
new file mode 100644
index 0000000000000000000000000000000000000000..e7718825d9737a7cfa11dad90ed75c6d43488f39
--- /dev/null
+++ b/movie-group-8/src/views/FilmDetails.vue
@@ -0,0 +1,168 @@
+<template>
+    <div class="film-details">
+      <button class="back-button" @click="$router.back()">← Back</button>
+  
+      <div v-if="loading" class="loading">Loading movie...</div>
+      <div v-else-if="error" class="error">Error: {{ error }}</div>
+  
+      <div v-else class="details-container">
+        <div class="poster-container">
+          <img
+            v-if="movie.poster_path"
+            :src="`https://image.tmdb.org/t/p/w500${movie.poster_path}`"
+            :alt="`${movie.title} poster`"
+            class="poster"
+          />
+        </div>
+  
+        <div class="info-container">
+          <h1 class="title">{{ movie.title }}</h1>
+          <p class="release-date">{{ formatDate(movie.release_date) }}</p>
+          <p class="overview">{{ movie.overview }}</p>
+  
+          <div v-if="trailerUrl" class="trailer">
+            <h2>Trailer</h2>
+            <iframe
+              :src="trailerUrl"
+              frameborder="0"
+              allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
+              allowfullscreen
+            ></iframe>
+          </div>
+        </div>
+      </div>
+    </div>
+  </template>
+  
+  <script setup>
+  import { ref, onMounted } from 'vue'
+  import { useRoute } from 'vue-router'
+  
+  const route = useRoute()
+  const movie = ref(null)
+  const trailerUrl = ref('')
+  const loading = ref(true)
+  const error = ref('')
+  
+  function formatDate(dateString) {
+    if (!dateString) return 'Unknown'
+    return new Date(dateString).toLocaleDateString(undefined, {
+      year: 'numeric',
+      month: 'long',
+      day: 'numeric'
+    })
+  }
+  
+  async function fetchMovieDetails(id) {
+    try {
+      const res = await fetch(
+        `${import.meta.env.VITE_TMDB_BASE}/movie/${id}?api_key=${import.meta.env.VITE_TMDB_API_KEY}`
+      )
+      if (!res.ok) throw new Error('Failed to fetch movie details')
+      movie.value = await res.json()
+    } catch (err) {
+      error.value = err.message
+    }
+  }
+  
+  async function fetchMovieVideos(id) {
+    try {
+      const res = await fetch(
+        `${import.meta.env.VITE_TMDB_BASE}/movie/${id}/videos?api_key=${import.meta.env.VITE_TMDB_API_KEY}`
+      )
+      if (!res.ok) throw new Error('Failed to fetch movie videos')
+      const data = await res.json()
+      const trailer = data.results.find(v => v.type === 'Trailer' && v.site === 'YouTube')
+      if (trailer) {
+        trailerUrl.value = `https://www.youtube.com/embed/${trailer.key}`
+      }
+    } catch {
+      // ignore trailer errors
+    }
+  }
+  
+  onMounted(async () => {
+    const id = route.params.id
+    await fetchMovieDetails(id)
+    await fetchMovieVideos(id)
+    loading.value = false
+  })
+  </script>
+  
+  <style scoped>
+  .film-details {
+    background-color: #121212;
+    color: #ffffff;
+    min-height: 100vh;
+    padding: 2rem;
+    box-sizing: border-box;
+  }
+  
+  .back-button {
+    color: #ffffff;
+    background: transparent;
+    margin-bottom: 1rem;
+    font-size: 1rem;
+  }
+  
+  .loading,
+  .error {
+    color: #ffffff;
+    text-align: center;
+    margin: 2rem 0;
+  }
+  
+  .details-container {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 2rem;
+    background-color: #1e1e1e;
+    padding: 2rem;
+    border-radius: 8px;
+    max-width: 900px;
+    margin: 2rem auto 0;
+  }
+  
+  .poster-container {
+    flex: 0 0 300px;
+  }
+  
+  .poster {
+    width: 100%;
+    border-radius: 4px;
+  }
+  
+  .info-container {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+  }
+  
+  .title {
+    font-size: 2rem;
+    margin: 0 0 0.5rem;
+  }
+  
+  .release-date {
+    color: #bbbbbb;
+    margin-bottom: 1rem;
+  }
+  
+  .overview {
+    color: #dddddd;
+    line-height: 1.6;
+    margin-bottom: 1.5rem;
+  }
+  
+  .trailer h2 {
+    margin-bottom: 0.5rem;
+    color: #ffffff;
+  }
+  
+  .trailer iframe {
+    width: 100%;
+    height: 300px;
+    border-radius: 8px;
+    border: none;
+  }
+  </style>
\ No newline at end of file
diff --git a/movie-group-8/src/views/Films.vue b/movie-group-8/src/views/Films.vue
index 3f3aee48247556da2a8e6c5b0598ebc70359d515..31474cbb988dd844fe1c2a8548fef94c70db2bfa 100644
--- a/movie-group-8/src/views/Films.vue
+++ b/movie-group-8/src/views/Films.vue
@@ -1,8 +1,106 @@
+<template>
+  <div class="films-container">
+    <!-- Centered search bar pushed down slightly -->
+    <div class="search-wrapper">
+      <input
+        v-model="term"
+        @keyup.enter="onSearch"
+        placeholder="Search movies…"
+        class="search-input"
+      />
+    </div>
+
+    <div v-if="loading" class="loading">Loading…</div>
+    <div v-else-if="error" class="error">Error: {{ error.message }}</div>
+
+    <!-- Movie grid -->
+    <MovieList :movies="results" />
+  </div>
+</template>
+
 <script setup>
-import TopRatedMovies from '@/components/TopRatedMovies.vue'
+import { ref, onMounted } from 'vue'
+import axios from 'axios'
+import MovieList from '../components/MovieList.vue'
+
+const API_KEY = import.meta.env.VITE_TMDB_API_KEY
+const BASE    = import.meta.env.VITE_TMDB_BASE
+
+const term    = ref('')
+const results = ref([])
+const loading = ref(false)
+const error   = ref(null)
+
+async function search(query) {
+  loading.value = true
+  error.value   = null
+  try {
+    const { data } = await axios.get(`${BASE}/search/movie`, {
+      params: { api_key: API_KEY, query }
+    })
+    results.value = data.results
+  } catch (e) {
+    error.value = e
+  } finally {
+    loading.value = false
+  }
+}
+
+async function fetchPopular() {
+  loading.value = true
+  error.value   = null
+  try {
+    const { data } = await axios.get(`${BASE}/movie/popular`, {
+      params: { api_key: API_KEY }
+    })
+    results.value = data.results
+  } catch (e) {
+    error.value = e
+  } finally {
+    loading.value = false
+  }
+}
+
+function onSearch() {
+  if (term.value.trim()) {
+    search(term.value)
+  } else {
+    fetchPopular()
+  }
+}
+
+onMounted(fetchPopular)
 </script>
 
-<template>
-  <TopRatedMovies />
-</template>
+<style scoped>
+.films-container {
+  padding-top: 6rem; /* adjust to nav height + spacing */
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  width: 100%;
+}
+
+.search-wrapper {
+  width: 100%;
+  max-width: 500px;
+  margin-bottom: 1.5rem;
+  display: flex;
+  justify-content: center;
+}
+
+.search-input {
+  width: 100%;
+  padding: 0.75rem 1rem;
+  font-size: 1.1rem;
+  border: 1px solid #ccc;
+  border-radius: 4px;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
 
+.loading,
+.error {
+  margin: 1rem 0;
+  font-weight: bold;
+}
+</style>
diff --git a/movie-group-8/src/views/Login.vue b/movie-group-8/src/views/Login.vue
index 103aadffb63ab10d38b6133399466015312d108a..eecffe4823239b2c0feac6450cd4b1938ed3d129 100644
--- a/movie-group-8/src/views/Login.vue
+++ b/movie-group-8/src/views/Login.vue
@@ -25,7 +25,7 @@
   
             <div class="py-3 flex items-center text-xs text-gray-400 uppercase before:flex-1 before:border-t before:border-gray-200 before:me-6 after:flex-1 after:border-t after:border-gray-200 after:ms-6 dark:text-neutral-500 dark:before:border-neutral-600 dark:after:border-neutral-600">Or</div>
   
-            <form @submit.prevent="register">
+            <form @submit.prevent="login">
               <div class="grid gap-y-4">
                 <div>
                   <label class="block text-sm mb-2 dark:text-white">Email Address</label>
@@ -44,7 +44,7 @@
 
                 <button 
                     type="submit" 
-                    @click="register"
+                    @click="login"
                     :disabled="loading"
                     class="w-full py-3 bg-blue-600 text-white rounded-lg flex justify-center items-center gap-2 hover:bg-blue-700 transition duration-300 disabled:opacity-50 disabled:pointer-events-none"
                     >
@@ -73,12 +73,12 @@
   const router = useRouter();
   const loading = ref(false);
   
-  const register = async () => {
+  const login = async () => {
     try {
       loading.value = true;
       const auth = getAuth();
       await signInWithEmailAndPassword(auth, email.value, password.value);
-      console.log('Successfully registered!');
+      console.log('Successfully logged in!');
       router.push('/films');
     } catch (error) {
       console.error(error);