├── .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 | 35 |
36 |
37 | 74 |
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 | 98 | 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 | {data.current.condition.text} 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 | {day.day.condition.text} 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 | 256 | 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 | --------------------------------------------------------------------------------