├── .eslintrc.cjs
├── .gitignore
├── README.md
├── SECURITY.md
├── index.html
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
├── Background.png
├── android-chrome-192x192.png
├── android-chrome-512x512.png
├── apple-touch-icon.png
├── bg.jpeg
├── favicon-16x16.png
├── favicon-32x32.png
├── favicon.ico
├── logo.jpeg
└── site.webmanifest
├── src
├── App.css
├── App.jsx
├── Component
│ ├── Cnsole.jsx
│ ├── Navbar.jsx
│ └── WeatherApp.jsx
├── assets
│ └── react.svg
├── index.css
└── main.jsx
├── tailwind.config.js
└── vite.config.js
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: { browser: true, es2020: true },
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:react/recommended',
7 | 'plugin:react/jsx-runtime',
8 | 'plugin:react-hooks/recommended',
9 | ],
10 | ignorePatterns: ['dist', '.eslintrc.cjs'],
11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
12 | settings: { react: { version: '18.2' } },
13 | plugins: ['react-refresh'],
14 | rules: {
15 | 'react-refresh/only-export-components': [
16 | 'warn',
17 | { allowConstantExport: true },
18 | ],
19 | },
20 | }
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 | .yarn/install-state.gz
8 |
9 | # testing
10 | /coverage
11 |
12 | # next.js
13 | /.next/
14 | /out/
15 |
16 | # production
17 | /build
18 |
19 | # misc
20 | .DS_Store
21 | *.pem
22 |
23 | # debug
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React-interview-app
2 |
3 |
4 | A Weather App Via Api | Vitejs, Axios, ReactQuery ,Tailwindcss , Phosphor Icons and Daisyui.
5 |
6 |
7 |
8 |
9 |
10 |
11 | :wrench: Features
12 | -----------------------
13 |
14 |
15 | The API site I used when creating the site is below:
16 |
17 | Weather Api
18 |
19 |
20 | You can access documents regarding the use of the API from the link.
21 |
22 | Docs.
23 |
24 |
25 |
26 |
27 | ## :book: How to use
28 | To clone and run this application, you'll need [Git](https://git-scm.com/downloads) and [ReactJS](https://reactjs.org/docs/getting-started.html) installed on your computer. From your command line:
29 |
30 | ```
31 | # Clone this repository
32 | $ git clone https://github.com/MehmetBozkir/React-interview-app.git
33 |
34 | # Go into the repository
35 | $ cd React-interview-app
36 |
37 | # Install dependencies
38 | $ npm install
39 |
40 | # Visit the page and get the API key
41 | $ https://www.weatherapi.com/
42 |
43 | # Include the personal API key you have in the .env folder
44 | $ echo "VITE_WEATHER_API=YOUR_API_KEY" > .env
45 |
46 | # Run the app
47 | $ npm run dev
48 | ```
49 | ## :link: Demo
50 | - Click Here to see and play by yourself a demo of the game.
51 |
52 |
53 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Mehmet Salih Bozkır
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Interview I Weather App
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "api",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "@phosphor-icons/react": "^2.0.15",
14 | "axios": "^1.6.7",
15 | "react": "^18.2.0",
16 | "react-dom": "^18.2.0",
17 | "react-icons": "^5.0.1",
18 | "react-query": "^3.39.3",
19 | "uuid": "^9.0.1"
20 | },
21 | "devDependencies": {
22 | "@types/react": "^18.2.43",
23 | "@types/react-dom": "^18.2.17",
24 | "@vitejs/plugin-react": "^4.2.1",
25 | "autoprefixer": "^10.4.17",
26 | "daisyui": "^4.6.2",
27 | "eslint": "^8.55.0",
28 | "eslint-plugin-react": "^7.33.2",
29 | "eslint-plugin-react-hooks": "^4.6.0",
30 | "eslint-plugin-react-refresh": "^0.4.5",
31 | "postcss": "^8.4.35",
32 | "tailwindcss": "^3.4.1",
33 | "vite": "^5.0.8"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/public/Background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MehmetBozkir/React-interview-app/ba2f1b1a95fe9bfc18389f60700624ab0f24c4be/public/Background.png
--------------------------------------------------------------------------------
/public/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MehmetBozkir/React-interview-app/ba2f1b1a95fe9bfc18389f60700624ab0f24c4be/public/android-chrome-192x192.png
--------------------------------------------------------------------------------
/public/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MehmetBozkir/React-interview-app/ba2f1b1a95fe9bfc18389f60700624ab0f24c4be/public/android-chrome-512x512.png
--------------------------------------------------------------------------------
/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MehmetBozkir/React-interview-app/ba2f1b1a95fe9bfc18389f60700624ab0f24c4be/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/bg.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MehmetBozkir/React-interview-app/ba2f1b1a95fe9bfc18389f60700624ab0f24c4be/public/bg.jpeg
--------------------------------------------------------------------------------
/public/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MehmetBozkir/React-interview-app/ba2f1b1a95fe9bfc18389f60700624ab0f24c4be/public/favicon-16x16.png
--------------------------------------------------------------------------------
/public/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MehmetBozkir/React-interview-app/ba2f1b1a95fe9bfc18389f60700624ab0f24c4be/public/favicon-32x32.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MehmetBozkir/React-interview-app/ba2f1b1a95fe9bfc18389f60700624ab0f24c4be/public/favicon.ico
--------------------------------------------------------------------------------
/public/logo.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MehmetBozkir/React-interview-app/ba2f1b1a95fe9bfc18389f60700624ab0f24c4be/public/logo.jpeg
--------------------------------------------------------------------------------
/public/site.webmanifest:
--------------------------------------------------------------------------------
1 | {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MehmetBozkir/React-interview-app/ba2f1b1a95fe9bfc18389f60700624ab0f24c4be/src/App.css
--------------------------------------------------------------------------------
/src/App.jsx:
--------------------------------------------------------------------------------
1 | import "./App.css";
2 | import WeatherApp from "./Component/WeatherApp";
3 | import Navbar from "./Component/Navbar";
4 | import Cnsole from "./Component/Cnsole";
5 | import Bgr from "/Background.png";
6 |
7 | function App() {
8 | return (
9 | <>
10 |
14 |
15 |
16 |
17 |
18 | >
19 | );
20 | }
21 |
22 | export default App;
23 |
--------------------------------------------------------------------------------
/src/Component/Cnsole.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useEffect } from "react";
3 |
4 | function Cnsole() {
5 | useEffect(() => {
6 | console.log(`
7 |
8 |
9 |
10 | ███ ███ ███████ ██ ██ ███ ███ ███████ ████████
11 | ████ ████ ██ ██ ██ ████ ████ ██ ██
12 | ██ ████ ██ █████ ███████ ██ ████ ██ █████ ██
13 | ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
14 | ██ ██ ███████ ██ ██ ██ ██ ███████ ██
15 |
16 |
17 | ███████ █████ ██ ██ ██ ██
18 | ██ ██ ██ ██ ██ ██ ██
19 | ███████ ███████ ██ ██ ███████
20 | ██ ██ ██ ██ ██ ██ ██
21 | ███████ ██ ██ ███████ ██ ██ ██
22 |
23 |
24 | ██████ ██████ ███████ ██ ██ ██ ██████
25 | ██ ██ ██ ██ ███ ██ ██ ██ ██ ██
26 | ██████ ██ ██ ███ █████ ██ ██████
27 | ██ ██ ██ ██ ███ ██ ██ ██ ██ ██
28 | ██████ ██████ ███████ ██ ██ ██ ██ ██
29 |
30 |
31 |
32 | Please visit my github page for code review : https://github.com/MehmetBozkir
33 |
34 |
35 |
36 | `);
37 | }, []);
38 |
39 | return <>>;
40 | }
41 |
42 | export default Cnsole;
43 |
--------------------------------------------------------------------------------
/src/Component/Navbar.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useState, useEffect } from "react";
3 | import Logo from "/logo.jpeg";
4 |
5 | function Navbar() {
6 | const [theme, setTheme] = useState(
7 | localStorage.getItem("theme") ? localStorage.getItem("theme") : "light"
8 | );
9 |
10 | const handleToggle = (e) => {
11 | if (e.target.checked) {
12 | setTheme("dark");
13 | } else {
14 | setTheme("light");
15 | }
16 | };
17 |
18 | const handleClick = () => {
19 | window.location.reload();
20 | };
21 |
22 | useEffect(() => {
23 | localStorage.setItem("theme", theme);
24 | const localTheme = localStorage.getItem("theme");
25 | document.querySelector("html").setAttribute("data-theme", localTheme);
26 | }, [theme]);
27 | return (
28 |
29 |
30 |
31 |
32 | {" "}
33 | iWeather
34 |
35 |
36 |
75 |
76 |
77 | );
78 | }
79 |
80 | export default Navbar;
81 |
--------------------------------------------------------------------------------
/src/Component/WeatherApp.jsx:
--------------------------------------------------------------------------------
1 | "use client";
2 | import { useQuery } from "react-query";
3 | import { v4 as uuidv4 } from "uuid";
4 | import { useState, useEffect } from "react";
5 | import Bgimage from "/bg.jpeg";
6 | import {
7 | ThermometerSimple,
8 | CloudRain,
9 | Wind,
10 | Drop,
11 | Sun,
12 | } from "@phosphor-icons/react";
13 |
14 | function WeatherApp() {
15 | const [location, setLocation] = useState("");
16 | const [position, setPosition] = useState({ latitude: null, longitude: null });
17 | const [isCurrentLocationUsed, setIsCurrentLocationUsed] = useState(false);
18 |
19 | useEffect(() => {
20 | if ("geolocation" in navigator) {
21 | navigator.geolocation.getCurrentPosition(function (position) {
22 | setPosition({
23 | latitude: position.coords.latitude,
24 | longitude: position.coords.longitude,
25 | });
26 | });
27 | } else {
28 | console.log("Geolocation is not available in your browser.");
29 | }
30 | }, []);
31 |
32 | useEffect(() => {
33 | if (isCurrentLocationUsed) {
34 | setLocation(`${position.latitude},${position.longitude}`);
35 |
36 | const timeout = setTimeout(() => {
37 | refetch();
38 |
39 | setIsCurrentLocationUsed(false);
40 | }, 100);
41 |
42 | return () => clearTimeout(timeout);
43 | }
44 | }, [isCurrentLocationUsed]);
45 |
46 | const fetchData = useQuery(
47 | [],
48 | () => {
49 | return fetch(
50 | `https://api.weatherapi.com/v1/forecast.json?key=${
51 | import.meta.env.VITE_WEATHER_API
52 | }&q=${location}&days=3&aqi=yes&alerts=yes`
53 | ).then((response) => response.json());
54 | },
55 | {
56 | enabled: false,
57 | }
58 | );
59 |
60 | const { data, isLoading, refetch } = fetchData;
61 |
62 | const handeLocationChange = (event) => {
63 | setLocation(event.target.value);
64 | };
65 |
66 | if (isLoading) {
67 | return (
68 |
69 |
70 |
71 | );
72 | }
73 |
74 | if (data && data.error) {
75 | return (
76 |
77 |
78 |
79 |
80 | Welcome to TypeWeather {" "}
81 |
82 |
83 | Choose a location to see the weather forecast
84 |
85 |
92 |
refetch()}
95 | >
96 | SEARCH
97 |
98 |
{
101 | setIsCurrentLocationUsed(true);
102 | }}
103 | >
104 | MY LOCATION
105 |
106 |
107 |
An Error Occurred
108 |
109 |
110 | Cause : {data.error.message}
111 |
112 |
113 |
114 |
115 |
116 | );
117 | }
118 |
119 | if (data) {
120 | return (
121 | <>
122 |
123 |
124 |
125 |
129 |
130 |
131 | {data.location.name} / {data.location.country}
132 |
133 | {data.location.localtime}
134 |
135 |
136 |
137 |
138 |
{data.current.temp_c}°c
139 | {data.current.condition.text}
140 |
141 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 | {" "}
156 | Thermal
157 | sensation
158 |
159 |
160 | {data.current.feelslike_c}°C
161 |
162 |
163 |
164 |
165 |
166 | {" "}
167 |
168 | Probability of rain
169 |
170 |
{data.current.vis_km}%
171 |
172 |
173 |
174 |
175 | {" "}
176 |
177 | Wind speed
178 |
179 |
180 | {data.current.wind_kph} km/h
181 |
182 |
183 |
184 |
185 |
186 | {" "}
187 |
188 | Air humidity
189 |
190 |
{data.current.humidity}%
191 |
192 |
193 |
194 |
195 | {" "}
196 |
197 | UV Index
198 |
199 |
{data.current.uv}
200 |
201 |
202 |
203 |
204 | {data && (
205 |
206 | {data.forecast.forecastday.map((day) => (
207 |
208 |
209 |
{day.date}
210 |
215 |
216 |
{day.day.maxtemp_c} °C
217 |
{day.day.mintemp_c} °C
218 |
219 |
220 |
221 | ))}
222 |
223 | )}
224 |
225 |
226 |
227 |
228 | >
229 | );
230 | }
231 |
232 | return (
233 | <>
234 |
235 |
236 |
237 |
238 | Welcome to TypeWeather {" "}
239 |
240 |
241 | Choose a location to see the weather forecast
242 |
243 |
250 |
refetch()}
253 | >
254 | SEARCH
255 |
256 |
{
259 | setIsCurrentLocationUsed(true);
260 | }}
261 | >
262 | MY LOCATION
263 |
264 |
265 |
266 |
267 | >
268 | );
269 | }
270 |
271 | export default WeatherApp;
272 |
--------------------------------------------------------------------------------
/src/assets/react.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 |
--------------------------------------------------------------------------------
/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.jsx'
4 | import './index.css'
5 | import { QueryClient, QueryClientProvider } from 'react-query'
6 |
7 | const queryClient = new QueryClient()
8 |
9 | ReactDOM.createRoot(document.getElementById('root')).render(
10 |
11 |
12 | ,
13 | )
14 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | export default {
3 | content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
4 | theme: {
5 | extend: {
6 | colors: {
7 | "sky-custom": "#8FB2F5",
8 | },
9 | fontFamily: {
10 | 'nunito': ['Nunito', 'sans-serif'],
11 | },
12 | minHeight: {
13 | 'screen': '92vh',
14 | }
15 | },
16 | },
17 | plugins: [require("daisyui")],
18 | };
19 |
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------