Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Create MovieFan - search the movie and check information about it #666

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions jobs/Frontend/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
VITE_API_KEY=eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJlNTFiMjAxNzAxNmE4MGVkMGUyNTliMzRjNTE4ZDlmOCIsIm5iZiI6MTYyMDY1MDYyNC4xNjQsInN1YiI6IjYwOTkyYTgwYTNkMDI3MDAzYTQxN2NhNiIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ._BphAcNuhdL3QtSAGoBNuEde6dfIdiV8BXLG_cMIBP4
VITE_API_URL=https://api.themoviedb.org/3
24 changes: 24 additions & 0 deletions jobs/Frontend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
36 changes: 25 additions & 11 deletions jobs/Frontend/Readme.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
# Mews frontend developer task
# MovieFan application where you can search the movie you want to know more about

You should start with creating a fork of the repository. When you're finished with the task, you should create a pull request.
To start the dev server:

Your task will be to create a simple movie search application. The application will have 2 views - search and movie detail. The search view is the default view, and should contain search input and display paginated list of found movies with a way to load additional batch. Search should start automatically after typing into the input is finished - there is no need for a search button. Clicking on a movie gets you to the movie detail view where detailed information about the movie should be listed.
- update the dependecies with `yarn`
- perform `yarn dev` after that

To retrieve information about movies, use [TheMovieDb API](https://developers.themoviedb.org/3/getting-started/introduction). You can use our api key to authorize requests:
```
03b8572954325680265531140190fd2a
```
To check the production:

## Required technologies
- run `yarn build`
- then `yarn preview`

To test your proficiency with the technologies we use the most, we require the solution to be written in React and TypeScript.
We use styled-components as our main CSS-in-JS framework, yet feel free to use other solutions you are more familiar with.
The use of any additional library is allowed and up to you.
To check unit tests:

- run `yarn test`
- or `yarn test:ci` for coverage

To check linting:

- run `yarn lint`

## More about my process of thinking when developing it

Besides required `React` and `TS`:

- Thought to not use any 3rd party state management for such a small project. It was enough for me to work with `useState()` and `useContext()` and to have a more lightweight bundle after all.
- Wanted to try out `Vite` bundler due to it's popularity, modern approach and cool features like per route bundling and prebundling deps.
- Decided to style everything with `styled-components` as your company's main styling tool.
- Configured `eslint/tslint` for the project, used `prettier` also.
- For unit testing I went with `jest` and `react-testing-library`. Covered a couple of tests to show my approach to that.
36 changes: 36 additions & 0 deletions jobs/Frontend/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import globals from "globals";
import js from "@eslint/js";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import react from "eslint-plugin-react";
import tseslint from "typescript-eslint";

export default tseslint.config(
{ ignores: ["dist"] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ["**/*.{ts,tsx}"],
settings: { react: { version: "18.3" } },
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
parserOptions: {
project: ["./tsconfig.node.json", "./tsconfig.app.json"],
tsconfigRootDir: import.meta.dirname,
},
},
plugins: {
"react-hooks": reactHooks,
"react-refresh": reactRefresh,
react: react,
},
rules: {
...reactHooks.configs.recommended.rules,
...react.configs["jsx-runtime"].rules,
"react-refresh/only-export-components": [
"warn",
{ allowConstantExport: true },
],
},
}
);
13 changes: 13 additions & 0 deletions jobs/Frontend/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/movie-fan.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>MovieFan</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
20 changes: 20 additions & 0 deletions jobs/Frontend/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export default {
testEnvironment: "jsdom",
extensionsToTreatAsEsm: [".ts", ".tsx"],
transform: {
"^.+\\.(ts|tsx)$": [
"ts-jest",
{
useESM: true,
tsconfig: "tsconfig.json",
},
],
},
moduleNameMapper: {
"@/(.*)": "<rootDir>/src/$1",
".+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$":
"identity-obj-proxy",
},
testMatch: ["<rootDir>/src/**/*.test.(ts|tsx)"],
preset: "ts-jest",
};
42 changes: 42 additions & 0 deletions jobs/Frontend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"name": "movies-search",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview",
"test": "jest",
"test:ci": "jest --coverage"
},
"dependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router": "^7.0.2",
"styled-components": "^6.1.13"
},
"devDependencies": {
"@eslint/js": "^9.15.0",
"@testing-library/dom": "^10.4.0",
"@testing-library/react": "^16.1.0",
"@types/jest": "^29.5.14",
"@types/node": "^22.10.1",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react": "^4.3.4",
"eslint": "^9.15.0",
"eslint-plugin-react": "^7.37.2",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.14",
"globals": "^15.12.0",
"identity-obj-proxy": "^3.0.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"ts-jest": "^29.2.5",
"typescript": "~5.6.2",
"typescript-eslint": "^8.15.0",
"vite": "^6.0.1"
}
}
56 changes: 56 additions & 0 deletions jobs/Frontend/public/movie-fan.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions jobs/Frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ThemeProvider } from "styled-components";
import MainLayout from "@/layouts/Main";
import Routing from "@/providers/Routing";
import theme from "@/styles/theme";
import GlobalStyles from "@/styles/global";
import ErrorCatcher from "@/providers/ErrorCatcher";
import ErrorFlash from "@/components/ErrorFlash/ErrorFlash";

function App() {
return (
<ThemeProvider theme={theme}>
<ErrorCatcher>
<ErrorFlash />
<GlobalStyles />
<MainLayout>
<Routing />
</MainLayout>
</ErrorCatcher>
</ThemeProvider>
);
}

export default App;
Binary file added jobs/Frontend/src/assets/movie-backdrop.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added jobs/Frontend/src/assets/movie-default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions jobs/Frontend/src/components/ErrorFlash/ErrorFlash.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { useContext } from "react";
import {
ErrorContainer,
ErrorMessage,
CloseButton,
} from "@/components/ErrorFlash/ErrorFlashStyle";
import ErrorContext from "@/providers/ErrorContext";

const ErrorFlash: React.FC = () => {
const { message, setMessage } = useContext(ErrorContext);

return (
message && (
<ErrorContainer>
<ErrorMessage>{message}</ErrorMessage>
<CloseButton onClick={() => setMessage("")}>&times;</CloseButton>
</ErrorContainer>
)
);
};

export default ErrorFlash;
36 changes: 36 additions & 0 deletions jobs/Frontend/src/components/ErrorFlash/ErrorFlashStyle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import styled from "styled-components";

export const ErrorContainer = styled.div`
position: fixed;
bottom: 16px;
left: 50%;
transform: translateX(-50%);
background: rgba(255, 0, 0, 0.8);
color: #fff;
padding: ${({ theme }) => theme.spacing(2)} ${({ theme }) => theme.spacing(3)};
border-radius: 4px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
display: flex;
align-items: center;
gap: ${({ theme }) => theme.spacing(2)};
z-index: 9999;
`;

export const ErrorMessage = styled.div`
font-size: 1rem;
font-weight: 500;
`;

export const CloseButton = styled.button`
background: none;
border: none;
color: #fff;
font-size: 1.2rem;
cursor: pointer;
line-height: 1;
padding: 8px;

&:hover {
opacity: 0.8;
}
`;
7 changes: 7 additions & 0 deletions jobs/Frontend/src/components/Footer/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Footer as StyledFooter } from "@/components/Footer/FooterStyle";

const Footer: React.FC = () => {
return <StyledFooter>Made by Daniel</StyledFooter>;
};

export default Footer;
10 changes: 10 additions & 0 deletions jobs/Frontend/src/components/Footer/FooterStyle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import styled from "styled-components";

export const Footer = styled.footer`
margin-top: auto;
padding: ${({ theme }) => theme.spacing(2)};
text-align: center;
background: transparent;
color: ${({ theme }) => theme.colors.textSecondary};
font-size: 0.9rem;
`;
14 changes: 14 additions & 0 deletions jobs/Frontend/src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {
AppName,
Header as StyledHeader,
} from "@/components/Header/HeaderStyle";

const Header: React.FC = () => {
return (
<StyledHeader>
<AppName>MovieFan</AppName>
</StyledHeader>
);
};

export default Header;
18 changes: 18 additions & 0 deletions jobs/Frontend/src/components/Header/HeaderStyle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import styled from "styled-components";

export const Header = styled.header`
width: 100%;
background: transparent;
backdrop-filter: blur(4px);
display: flex;
justify-content: center;
align-items: center;
padding: ${({ theme }) => theme.spacing(2)} 0;
`;

export const AppName = styled.h1`
margin: 0;
font-size: 1.8rem;
font-weight: 700;
color: ${({ theme }) => theme.colors.textPrimary};
`;
Loading