diff --git a/backend/config/middleware.js b/backend/config/middleware.js index 6af9f00a..2e389ed9 100644 --- a/backend/config/middleware.js +++ b/backend/config/middleware.js @@ -16,6 +16,11 @@ function hasCampaign(req, res, next){ }).catch((err) => res.json({status: "error", err})); } +function hasUser(req, res, next){ + +} + module.exports = { - hasCampaign + hasCampaign, + hasUser } \ No newline at end of file diff --git a/backend/models/User.js b/backend/models/User.js index 232b9722..abac13be 100755 --- a/backend/models/User.js +++ b/backend/models/User.js @@ -8,7 +8,8 @@ const UserSchema = new Schema({ password: { type: String, required: true }, date: { type: Date, default: Date.now}, admin: {type: Boolean, default: false}, - image: { type: String } + image: { type: String }, + settings: { type: Object } }); module.exports = mongoose.model('User', UserSchema); \ No newline at end of file diff --git a/backend/routes/user.js b/backend/routes/user.js index 6de0cb35..ab02d20a 100755 --- a/backend/routes/user.js +++ b/backend/routes/user.js @@ -8,6 +8,8 @@ const secret = require('../config/keys').secret; const rateLimitMiddleware = require("../config/rate-limiter"); const { default: jwtDecode } = require('jwt-decode'); +const { hasUser } = require('../config/middleware'); + const User = require("../models/User"); const upload = require("../config/storage"); @@ -96,6 +98,7 @@ router.post('/login', rateLimitMiddleware, (req, res) => { name: user.name, email: user.email, admin: user.admin, + settings: user.settings } jwt.sign(payload, secret, { expiresIn: 172800 @@ -151,4 +154,24 @@ router.get("/has-admin", (req, res) => { }); }); +router.post("/update-settings", passport.authenticate('jwt', {session: false}), (req, res) => { + User.updateOne(req.user, {settings: req.body.settings}).then(() => { + res.json({ + status: "ok", + settings: req.body.settings + }) + }).catch((err) => { + res.json({status: "error", msg: "internal"}) + }); +}); + +router.get('/get-settings', passport.authenticate('jwt', {session: false}), (req, res) => { + User.findOne(req.user).then((data) => { + res.json({ + status: "ok", + settings: data.settings + }); + }).catch((err) => res.json({status: "error", msg: "internal"})); +}) + module.exports = router; \ No newline at end of file diff --git a/client/src/App.vue b/client/src/App.vue index 2733ba0b..27f62da4 100644 --- a/client/src/App.vue +++ b/client/src/App.vue @@ -14,8 +14,6 @@ import { ImportModule, GetModulesToLoad } from './services/Modules' import { CreateWindow } from './services/Windows'; import { FetchVanillaResources } from './services/Resources'; -console.clear(); -console.log("%cLoaded!!!", "color: #22ff22; font-size: 24px"); LoadUser(); SetEmitter(emitter); diff --git a/client/src/assets/main.css b/client/src/assets/main.css index 69e9710a..1d744c5a 100644 --- a/client/src/assets/main.css +++ b/client/src/assets/main.css @@ -276,4 +276,20 @@ span.legendary { } span.artifact { color: var(--color-artifact); +} + +.form-container { + width: 100%; +} + +.form-element { + padding: 10px 0 10px 0; + margin: 0 10px 0 10px; + display: flex; + align-items: center; + border-bottom: 1px dashed var(--color-border); +} + +.form-element label { + flex-grow: 1; } \ No newline at end of file diff --git a/client/src/locale/ca.json b/client/src/locale/ca.json new file mode 100644 index 00000000..8074d47d --- /dev/null +++ b/client/src/locale/ca.json @@ -0,0 +1,3 @@ +{ + "main-menu": "Menú Principal" +} \ No newline at end of file diff --git a/client/src/locale/en.json b/client/src/locale/en.json index 19f5a5f2..b108643a 100644 --- a/client/src/locale/en.json +++ b/client/src/locale/en.json @@ -1,3 +1,11 @@ { - "main-menu": "Main Menu" + "main-menu": { + "main-menu": "Main Menu", + "campaigns": "Campaigns", + "cosmic-compendium": "The Cosmic Compendium", + "book-anvil": "Book Anvil", + "edit-profile": "Edit Profile", + "settings": "Settings", + "log-out": "Log Out" + } } \ No newline at end of file diff --git a/client/src/locale/es.json b/client/src/locale/es.json index 8074d47d..3cae136b 100644 --- a/client/src/locale/es.json +++ b/client/src/locale/es.json @@ -1,3 +1,11 @@ { - "main-menu": "Menú Principal" + "main-menu": { + "main-menu": "Menú Principal", + "campaigns": "Campañas", + "cosmic-compendium": "La Libreria Cósmica", + "book-anvil": "Forjador de Libros", + "edit-profile": "Editar Perfil", + "settings": "Ajustes", + "log-out": "Cerrar sesión" + } } \ No newline at end of file diff --git a/client/src/main.js b/client/src/main.js index 781bb3f6..11295efc 100644 --- a/client/src/main.js +++ b/client/src/main.js @@ -8,8 +8,10 @@ import router from './router' import EN from './locale/en.json' import ES from './locale/es.json' +import CA from './locale/ca.json' import mitt from 'mitt'; +import { GetUser, GetUserSetting } from './services/User' const emitter = mitt(); const app = createApp(App); @@ -22,12 +24,23 @@ app.config.globalProperties.rollWindows = { edit_profile: reactive([]), }; + +console.clear(); +console.log("%cLoaded!!!", "color: #22ff22; font-size: 24px"); + +// Determinem el locale +let locale = 'en'; +if(GetUser()) locale = await GetUserSetting('lang'); +console.log(locale); + const i18n = createI18n({ legacy: false, - locale: 'en', + locale, + fallbackLocale: 'en', messages: { en: EN, es: ES, + ca: CA } }); diff --git a/client/src/services/ContextMenu.js b/client/src/services/ContextMenu.js index 9e8785b7..c2ca283f 100644 --- a/client/src/services/ContextMenu.js +++ b/client/src/services/ContextMenu.js @@ -77,13 +77,24 @@ function PopulateContextMenu(val){ children.forEach((el) => contextMenu.appendChild(el)); } -function AddContextMenu(element, val){ +function AddContextMenu(element, val, options = {}){ element._dr_context = val; - element.addEventListener('contextmenu', (e) => { + + function show(e){ e.preventDefault(); PopulateContextMenu(val); Show(); - }); + if(options.dropdown){ + let rect = element.getBoundingClientRect(); + let contextMenu = document.getElementById('context-menu'); + contextMenu.style.top = rect.bottom + "px"; + contextMenu.style.left = rect.left + "px"; + console.log(rect.top); + } + } + + element.addEventListener('contextmenu', show); + if(options.dropdown) element.addEventListener('click', show); } diff --git a/client/src/services/User.js b/client/src/services/User.js index 12a6d60c..301550f8 100644 --- a/client/src/services/User.js +++ b/client/src/services/User.js @@ -24,6 +24,25 @@ async function HasAdmin(){ return response.data.status != "init"; } +function SetUserSetting(key, value){ + return new Promise((resolve, reject) => { + let user = GetUser() + if(!user.settings) user.settings = {}; + user.settings[key] = value; + Api().post('/user/update-settings', {settings: user.settings}).then(response => { + resolve(response.data.settings); + }); + }); +} + +function GetUserSetting(key){ + return new Promise((resolve, reject) => { + Api().get('/user/get-settings').then(response => { + resolve(response.data.settings[key]); + }); + }); +} + function GetUser(){ const token = localStorage.getItem('token'); @@ -66,5 +85,7 @@ export { LoadUser, IsAdmin, LogoutUser, - HasAdmin + HasAdmin, + GetUserSetting, + SetUserSetting } \ No newline at end of file diff --git a/client/src/services/Windows.js b/client/src/services/Windows.js index 8a68dd1b..1a9758ae 100644 --- a/client/src/services/Windows.js +++ b/client/src/services/Windows.js @@ -36,7 +36,7 @@ const defValues = { close: () => ClearWindow('edit_profile') }, 'settings': { - id: 'ettings', + id: 'settings', title: "Dragonroll settings", close: () => ClearWindow('settings') }, diff --git a/client/src/views/partials/Dropdown.vue b/client/src/views/partials/Dropdown.vue index 0ba40a1c..c9eb037c 100644 --- a/client/src/views/partials/Dropdown.vue +++ b/client/src/views/partials/Dropdown.vue @@ -1,35 +1,39 @@ diff --git a/client/src/views/partials/EditUserPartial.vue b/client/src/views/partials/EditUserPartial.vue index 8b634c55..0e6db396 100644 --- a/client/src/views/partials/EditUserPartial.vue +++ b/client/src/views/partials/EditUserPartial.vue @@ -78,9 +78,9 @@ onMounted(() => {
- - - + + +
diff --git a/client/src/views/windows/MainMenuWindow.vue b/client/src/views/windows/MainMenuWindow.vue index f66acb81..67e2aa47 100644 --- a/client/src/views/windows/MainMenuWindow.vue +++ b/client/src/views/windows/MainMenuWindow.vue @@ -82,13 +82,13 @@ function OpenBookAnvil(){ -

{{ $t("main-menu")}}

+

{{ $t("main-menu.main-menu")}}

- +
- - + +
diff --git a/client/src/views/windows/SettingsWindow.vue b/client/src/views/windows/SettingsWindow.vue index 4da69c74..ac8617a0 100644 --- a/client/src/views/windows/SettingsWindow.vue +++ b/client/src/views/windows/SettingsWindow.vue @@ -5,8 +5,8 @@ import { GetUser } from '@/services/User' import WindowHandle from '@/views/partials/WindowHandle.vue'; import Tabs from '../partials/Tabs.vue'; -import { I18nD, I18nN } from 'vue-i18n'; import Dropdown from '../partials/Dropdown.vue'; +import { GetUserSetting, SetUserSetting } from '../../services/User'; const handle = ref(null); @@ -17,20 +17,36 @@ let id = data.id; let rows = ref(["Account settings"]); +const languageOptions = ref(["English", "Spanish", "Catalan"]) const langSelector = ref(null); +const currentLanguage = ref(""); onBeforeMount(() => { + let codes = { + "en": "English", + "es": "Spanish", + "ca": "Catalan" + } + GetUserSetting('lang').then(value => { + currentLanguage.value = codes[value ?? 'en'] + console.log(currentLanguage.value) + }); if(GetUser().admin) rows.value.push("Site Administration"); }); onMounted(() => { SetupHandle(id, handle); - SetSize(id, {width: 500, height: 380}); + SetSize(id, {width: 400, height: 480}); ResetPosition(id, "center"); }); -function OnLanguageChange(){ - I18n.locale = langSelector.value.value; +async function OnLanguageChange(value){ + let codes = { + "English": "en", + "Spanish": "es", + "Catalan": "ca" + } + await SetUserSetting("lang", codes[value]); } @@ -42,8 +58,13 @@ function OnLanguageChange(){ +
+
+ + +
+
+ Hola @@ -54,9 +75,6 @@ function OnLanguageChange(){