diff --git a/gymboard-app/.env.development b/gymboard-app/.env.development new file mode 100644 index 0000000..e7db5ec --- /dev/null +++ b/gymboard-app/.env.development @@ -0,0 +1,3 @@ +API_URL=http://localhost:8080 +CDN_URL=http://localhost:8082 +SEARCH_URL=http://localhost:8081 diff --git a/gymboard-app/.env.production b/gymboard-app/.env.production new file mode 100644 index 0000000..b0f9279 --- /dev/null +++ b/gymboard-app/.env.production @@ -0,0 +1,3 @@ +API_URL=https://api.gymboard.com +CDN_URL=https://cdn.gymboard.com +SEARCH_URL=https://search.gymboard.com diff --git a/gymboard-app/package-lock.json b/gymboard-app/package-lock.json index a2f394c..d0da756 100644 --- a/gymboard-app/package-lock.json +++ b/gymboard-app/package-lock.json @@ -11,6 +11,7 @@ "@quasar/cli": "^2.0.0", "@quasar/extras": "^1.0.0", "axios": "^0.21.1", + "dotenv": "^16.0.3", "luxon": "^3.2.1", "moment": "^2.29.4", "pinia": "^2.0.11", @@ -2166,6 +2167,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/dotenv": { + "version": "16.0.3", + "resolved": "http://192.168.88.248:8081/repository/npm-public/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -7937,6 +7947,11 @@ "is-obj": "^2.0.0" } }, + "dotenv": { + "version": "16.0.3", + "resolved": "http://192.168.88.248:8081/repository/npm-public/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==" + }, "eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", diff --git a/gymboard-app/package.json b/gymboard-app/package.json index f714341..9571ee6 100644 --- a/gymboard-app/package.json +++ b/gymboard-app/package.json @@ -14,6 +14,7 @@ "@quasar/cli": "^2.0.0", "@quasar/extras": "^1.0.0", "axios": "^0.21.1", + "dotenv": "^16.0.3", "luxon": "^3.2.1", "moment": "^2.29.4", "pinia": "^2.0.11", diff --git a/gymboard-app/quasar.config.js b/gymboard-app/quasar.config.js index 4b15218..70c8a04 100644 --- a/gymboard-app/quasar.config.js +++ b/gymboard-app/quasar.config.js @@ -12,6 +12,8 @@ const { configure } = require('quasar/wrappers'); const path = require('path'); const { withCtx } = require('vue'); +require('dotenv').config(); + module.exports = configure(function (ctx) { return { eslint: { @@ -65,7 +67,9 @@ module.exports = configure(function (ctx) { // publicPath: '/', // analyze: true, env: { - API: ctx.dev ? 'http://localhost:8080' : 'https://api.gymboard.com', + API_URL: process.env.API_URL, + CDN_URL: process.env.CDN_URL, + SEARCH_URL: process.env.SEARCH_URL, }, // rawDefine: {} // ignorePublicFolder: true, diff --git a/gymboard-app/src/api/main/auth.ts b/gymboard-app/src/api/main/auth.ts index 1e7ff48..575d258 100644 --- a/gymboard-app/src/api/main/auth.ts +++ b/gymboard-app/src/api/main/auth.ts @@ -1,6 +1,7 @@ import {api} from 'src/api/main/index'; import {AuthStoreType} from 'stores/auth-store'; import Timeout = NodeJS.Timeout; +import {WeightUnit} from 'src/api/main/submission'; export interface User { id: string; @@ -21,7 +22,7 @@ export interface UserPersonalDetails { userId: string; birthDate?: string; currentWeight?: number; - currentWeightUnit?: number; + currentWeightUnit?: WeightUnit; currentMetricWeight?: number; sex: PersonSex; } diff --git a/gymboard-app/src/api/main/index.ts b/gymboard-app/src/api/main/index.ts index 2255b8d..de65c54 100644 --- a/gymboard-app/src/api/main/index.ts +++ b/gymboard-app/src/api/main/index.ts @@ -3,12 +3,9 @@ import GymsModule from 'src/api/main/gyms'; import ExercisesModule from 'src/api/main/exercises'; import LeaderboardsModule from 'src/api/main/leaderboards'; import AuthModule from 'src/api/main/auth'; - -export const BASE_URL = 'http://localhost:8080'; - -// TODO: Figure out how to get the base URL from environment. +console.log(process.env); export const api = axios.create({ - baseURL: BASE_URL, + baseURL: process.env.API_URL, }); class GymboardApi { diff --git a/gymboard-app/src/boot/i18n.ts b/gymboard-app/src/boot/i18n.ts index 5b86bf2..b7fb451 100644 --- a/gymboard-app/src/boot/i18n.ts +++ b/gymboard-app/src/boot/i18n.ts @@ -37,7 +37,7 @@ export default boot(({ app }) => { } // Temporary override if you want to test a particular locale. - i18n.global.locale.value = 'nl-NL'; + // i18n.global.locale.value = 'nl-NL'; // Set i18n instance on app app.use(i18n); diff --git a/gymboard-app/src/components/EditablePropertyRow.vue b/gymboard-app/src/components/EditablePropertyRow.vue index 4d3ea99..29d75a6 100644 --- a/gymboard-app/src/components/EditablePropertyRow.vue +++ b/gymboard-app/src/components/EditablePropertyRow.vue @@ -2,11 +2,12 @@
{{ label }} -
+
@@ -14,6 +15,16 @@
+ +
+ +
@@ -24,6 +35,8 @@ interface Props { label: string; inputType?: any; modelValue: string | number | boolean | DateTime; + selectOptions?: Array; + numberInputStep?: number; } defineProps(); const emits = defineEmits(['update:modelValue']); diff --git a/gymboard-app/src/i18n/en-US/index.ts b/gymboard-app/src/i18n/en-US/index.ts index 8e9b72b..aaae410 100644 --- a/gymboard-app/src/i18n/en-US/index.ts +++ b/gymboard-app/src/i18n/en-US/index.ts @@ -48,11 +48,25 @@ export default { }, userSettingsPage: { title: 'Account Settings', + password: 'Password', + passwordHint: 'Set a new password for your account.', + updatePassword: 'Update Password', + passwordUpdated: 'Password updated.', + passwordInvalid: 'Invalid password.', personalDetails: { - birthDate: 'Date of Birth' + title: 'Personal Details', + birthDate: 'Date of Birth', + sex: 'Sex', + sexMale: 'Male', + sexFemale: 'Female', + sexUnknown: 'Prefer not to say', + currentWeight: 'Current Weight', + currentWeightUnit: 'Current Weight Unit' }, preferences: { - accountPrivate: 'Private Account' + title: 'Preferences', + accountPrivate: 'Private', + language: 'Language' }, save: 'Save', undo: 'Undo' @@ -65,5 +79,9 @@ export default { }, generalErrors: { apiError: 'An API error occurred. Please try again later.' + }, + weightUnit: { + kilograms: 'Kilograms', + pounds: 'Pounds' } }; diff --git a/gymboard-app/src/i18n/nl-NL/index.ts b/gymboard-app/src/i18n/nl-NL/index.ts index 708f388..12e33fc 100644 --- a/gymboard-app/src/i18n/nl-NL/index.ts +++ b/gymboard-app/src/i18n/nl-NL/index.ts @@ -17,6 +17,7 @@ export default { password: 'Wachtwoord', logIn: 'Inloggen', createAccount: 'Account aanmaken', + authFailed: 'Ongeldige inloggegevens.', }, indexPage: { searchHint: 'Zoek een sportschool', @@ -39,8 +40,48 @@ export default { submit: 'Sturen', }, }, + userPage: { + notFound: { + title: 'Gebruiker niet gevonden', + description: 'Wij konden de gebruiker voor wie jij zoekt niet vinden, helaas.' + } + }, + userSettingsPage: { + title: 'Account instellingen', + password: 'Wachtwoord', + passwordHint: 'Stel een nieuw wachtwoord voor je account in.', + updatePassword: 'Wachtwoord bijwerken', + passwordUpdated: 'Wachtwoord succesvol bijgewerkt.', + passwordInvalid: 'Ongeldig wachtwoord.', + personalDetails: { + title: 'Persoonlijke gegevens', + birthDate: 'Geboortedatum', + sex: 'Geslacht', + sexMale: 'Mannelijk', + sexFemale: 'Vrouwelijk', + sexUnknown: 'Liever niet zeggen', + currentWeight: 'Huidige gewicht', + currentWeightUnit: 'Eenheden van huidige gewicht' + }, + preferences: { + title: 'Voorkeuren', + accountPrivate: 'Privaat', + language: 'Taal' + }, + save: 'Opslaan', + undo: 'Terugzetten' + }, accountMenuItem: { logIn: 'Inloggen', + profile: 'Profile', + settings: 'Instellingen', logOut: 'Uitloggen', }, + generalErrors: { + apiError: 'Er is een API fout opgetreden. Probeer het nogmals later.' + }, + weightUnit: { + kilograms: 'Kilogram', + pounds: 'Ponden' + } }; diff --git a/gymboard-app/src/pages/auth/LoginPage.vue b/gymboard-app/src/pages/auth/LoginPage.vue index 11a3c95..d3f428c 100644 --- a/gymboard-app/src/pages/auth/LoginPage.vue +++ b/gymboard-app/src/pages/auth/LoginPage.vue @@ -40,7 +40,7 @@ @@ -78,7 +78,7 @@ const passwordVisible = ref(false); /** * The main login function. It attempts to log in the user, and gracefully * handles failures. - * + * * Upon successful login, we set the app's locale to the user's preferred * locale, and then redirect to the pre-configured next URL (if there is one). */ @@ -87,8 +87,8 @@ async function tryLogin() { await api.auth.login(authStore, loginModel.value); // Set the locale to the user's preferred locale. - i18n.locale.value = resolveLocale(authStore.user?.preferences?.locale); - + i18n.locale.value = resolveLocale(authStore.user?.preferences?.locale).value; + // Redirect back to whatever was set as the next URL. const dest = route.query.next ? decodeURIComponent(route.query.next as string) diff --git a/gymboard-app/src/pages/auth/UserSettingsPage.vue b/gymboard-app/src/pages/auth/UserSettingsPage.vue index eed636b..61fe02b 100644 --- a/gymboard-app/src/pages/auth/UserSettingsPage.vue +++ b/gymboard-app/src/pages/auth/UserSettingsPage.vue @@ -1,17 +1,58 @@ +