diff --git a/.gitignore b/.gitignore index eea34196..a9de8b3a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,12 @@ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. +.env + # dependencies /node_modules -/frontend/node_modules/.cache -/frontend/node_modules/** +/frontend/node_modules/ +/frontend/node_modules/.cache/ +/backend/.secrets/ /.pnp .pnp.js diff --git a/backend/src/main/java/com/kurttekin/can/job_track/infrastructure/security/config/CorsConfig.java b/backend/src/main/java/com/kurttekin/can/job_track/infrastructure/security/config/CorsConfig.java index edad0876..d6b0c847 100644 --- a/backend/src/main/java/com/kurttekin/can/job_track/infrastructure/security/config/CorsConfig.java +++ b/backend/src/main/java/com/kurttekin/can/job_track/infrastructure/security/config/CorsConfig.java @@ -14,7 +14,6 @@ @Configuration public class CorsConfig { - // if no env var, default to localhost:3000 for react @Value("${ALLOWED_ORIGINS:http://localhost:3000}") private String allowedOrigins; diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index 511ffefc..31213537 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -8,9 +8,9 @@ app.jwtExpirationInMs=86400000 # jwt signing key -gemini.api.key=${GEMINI_API_KEY} +gemini.api.key=${GEMINI_API_KEY:"GEMINI_API_KEY"} -ALLOWED_ORIGINS=${ALLOWED_ORIGINS} +#ALLOWED_ORIGINS=${ALLOWED_ORIGINS} server.port=${PORT:8080} #server.ssl.key-store=classpath:keystore.p12 #server.ssl.key-store-password=${KEY_STORE_PASS} diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 09ad9502..131a7839 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -12,8 +12,10 @@ "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", "axios": "^1.7.7", + "i18next": "^23.16.4", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-i18next": "^15.1.0", "react-icons": "^5.3.0", "react-modal": "^3.16.1", "react-router-dom": "^6.27.0", @@ -9884,6 +9886,15 @@ "node": ">=12" } }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "license": "MIT", + "dependencies": { + "void-elements": "3.1.0" + } + }, "node_modules/html-webpack-plugin": { "version": "5.6.3", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.3.tgz", @@ -10037,6 +10048,29 @@ "node": ">=10.17.0" } }, + "node_modules/i18next": { + "version": "23.16.4", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.16.4.tgz", + "integrity": "sha512-9NIYBVy9cs4wIqzurf7nLXPyf3R78xYbxExVqHLK9od3038rjpyOEzW+XB130kZ1N4PZ9inTtJ471CRJ4Ituyg==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.2" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -15915,6 +15949,28 @@ "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==", "license": "MIT" }, + "node_modules/react-i18next": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.1.0.tgz", + "integrity": "sha512-zj3nJynMnZsy2gPZiOTC7XctCY5eQGqT3tcKMmfJWC9FMvgd+960w/adq61j8iPzpwmsXejqID9qC3Mqu1Xu2Q==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "html-parse-stringify": "^3.0.1" + }, + "peerDependencies": { + "i18next": ">= 23.2.3", + "react": ">= 16.8.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/react-icons": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.3.0.tgz", @@ -18478,9 +18534,9 @@ } }, "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "license": "Apache-2.0", "peer": true, "bin": { @@ -18488,7 +18544,7 @@ "tsserver": "bin/tsserver" }, "engines": { - "node": ">=14.17" + "node": ">=4.2.0" } }, "node_modules/unbox-primitive": { @@ -18749,6 +18805,15 @@ "d3-timer": "^3.0.1" } }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index 4e5c98ad..36c89342 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -8,8 +8,10 @@ "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", "axios": "^1.7.7", + "i18next": "^23.16.4", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-i18next": "^15.1.0", "react-icons": "^5.3.0", "react-modal": "^3.16.1", "react-router-dom": "^6.27.0", diff --git a/frontend/src/components/Home.js b/frontend/src/components/Home.js index c356ae5f..5618c90b 100644 --- a/frontend/src/components/Home.js +++ b/frontend/src/components/Home.js @@ -5,16 +5,17 @@ import filterImage from '../assets/filter.png'; import starsImage from '../assets/stars.png'; import goalsImage from '../assets/goal.png'; import buyMeACoffeeImage from '../assets/buy-me-a-beer.png'; -import seperator from '../assets/seperator.png'; +import separator from '../assets/seperator.png'; import { useNavigate } from 'react-router-dom'; import { AuthContext } from '../contexts/AuthContext'; import styled from "styled-components"; import screenshotImage from '../assets/screenshot1.png'; +import { useTranslation } from 'react-i18next'; +import { Trans } from 'react-i18next'; const Button = styled.button` margin-right: 0; margin-left: 0; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - &:hover { background-color: #333; } @@ -23,6 +24,7 @@ const Button = styled.button` const Home = () => { const navigate = useNavigate(); const { isLoggedIn } = useContext(AuthContext); + const { t } = useTranslation(); // Use the hook const handleRegisterClick = () => { navigate('/register'); @@ -32,14 +34,14 @@ const Home = () => {
Add jobs from any source you want
+{t('illustrations.job_source')}
Comment on your applications, star your favorites
+{t('illustrations.comment')}
Filter and/or sort to view your applications
+{t('illustrations.filter')}
Land a job (hopefully)
+{t('illustrations.goal')}
- ⚹One convenient place you can access from anywhere and any
- device.
- ⚹Stay organized, never miss an opportunity.
- ⚹Generate personalized interview questions to prepare effectively.
- ⚹Analyze your application stats.
-
+ ⚹
+ ⚹
+ ⚹
+ ⚹
- This service is designed to help people in job hunt without any cost, if you want to support, - here is donation button stuff. + {t('support.text')}
- ); -}; -export default Home; + ); + }; + +export default Home; \ No newline at end of file diff --git a/frontend/src/components/LanguageSwitcher.js b/frontend/src/components/LanguageSwitcher.js index 979c270c..c75e3493 100644 --- a/frontend/src/components/LanguageSwitcher.js +++ b/frontend/src/components/LanguageSwitcher.js @@ -1,16 +1,33 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import styled from "styled-components"; + +const Button = styled.button` + margin-right: 2px; + margin-left: 0; + padding: 4px; + background-color: transparent; + color: black; + //border: 1px solid #333; + //box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + &:hover { + background-color: #f5f5f5; + } +`; + const LanguageSwitcher = () => { - const { i18n } = useTranslation(); + const { i18n } = useTranslation(); - const changeLanguage = (language) => { - i18n.changeLanguage(language); - }; + const changeLanguage = (language) => { + i18n.changeLanguage(language); + }; - return ( -