This commit is contained in:
BinarySandia04 2024-09-22 17:51:04 +02:00
parent aa88bb9802
commit 58c04ec3b9
17 changed files with 171 additions and 42 deletions

View File

@ -16,6 +16,11 @@ function hasCampaign(req, res, next){
}).catch((err) => res.json({status: "error", err})); }).catch((err) => res.json({status: "error", err}));
} }
module.exports = { function hasUser(req, res, next){
hasCampaign
}
module.exports = {
hasCampaign,
hasUser
} }

View File

@ -8,7 +8,8 @@ const UserSchema = new Schema({
password: { type: String, required: true }, password: { type: String, required: true },
date: { type: Date, default: Date.now}, date: { type: Date, default: Date.now},
admin: {type: Boolean, default: false}, admin: {type: Boolean, default: false},
image: { type: String } image: { type: String },
settings: { type: Object }
}); });
module.exports = mongoose.model('User', UserSchema); module.exports = mongoose.model('User', UserSchema);

View File

@ -8,6 +8,8 @@ const secret = require('../config/keys').secret;
const rateLimitMiddleware = require("../config/rate-limiter"); const rateLimitMiddleware = require("../config/rate-limiter");
const { default: jwtDecode } = require('jwt-decode'); const { default: jwtDecode } = require('jwt-decode');
const { hasUser } = require('../config/middleware');
const User = require("../models/User"); const User = require("../models/User");
const upload = require("../config/storage"); const upload = require("../config/storage");
@ -96,6 +98,7 @@ router.post('/login', rateLimitMiddleware, (req, res) => {
name: user.name, name: user.name,
email: user.email, email: user.email,
admin: user.admin, admin: user.admin,
settings: user.settings
} }
jwt.sign(payload, secret, { jwt.sign(payload, secret, {
expiresIn: 172800 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; module.exports = router;

View File

@ -14,8 +14,6 @@ import { ImportModule, GetModulesToLoad } from './services/Modules'
import { CreateWindow } from './services/Windows'; import { CreateWindow } from './services/Windows';
import { FetchVanillaResources } from './services/Resources'; import { FetchVanillaResources } from './services/Resources';
console.clear();
console.log("%cLoaded!!!", "color: #22ff22; font-size: 24px");
LoadUser(); LoadUser();
SetEmitter(emitter); SetEmitter(emitter);

View File

@ -277,3 +277,19 @@ span.legendary {
span.artifact { span.artifact {
color: var(--color-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;
}

View File

@ -0,0 +1,3 @@
{
"main-menu": "Menú Principal"
}

View File

@ -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"
}
} }

View File

@ -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"
}
} }

View File

@ -8,8 +8,10 @@ import router from './router'
import EN from './locale/en.json' import EN from './locale/en.json'
import ES from './locale/es.json' import ES from './locale/es.json'
import CA from './locale/ca.json'
import mitt from 'mitt'; import mitt from 'mitt';
import { GetUser, GetUserSetting } from './services/User'
const emitter = mitt(); const emitter = mitt();
const app = createApp(App); const app = createApp(App);
@ -22,12 +24,23 @@ app.config.globalProperties.rollWindows = {
edit_profile: reactive([]), 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({ const i18n = createI18n({
legacy: false, legacy: false,
locale: 'en', locale,
fallbackLocale: 'en',
messages: { messages: {
en: EN, en: EN,
es: ES, es: ES,
ca: CA
} }
}); });

View File

@ -77,13 +77,24 @@ function PopulateContextMenu(val){
children.forEach((el) => contextMenu.appendChild(el)); children.forEach((el) => contextMenu.appendChild(el));
} }
function AddContextMenu(element, val){ function AddContextMenu(element, val, options = {}){
element._dr_context = val; element._dr_context = val;
element.addEventListener('contextmenu', (e) => {
function show(e){
e.preventDefault(); e.preventDefault();
PopulateContextMenu(val); PopulateContextMenu(val);
Show(); 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);
} }

View File

@ -24,6 +24,25 @@ async function HasAdmin(){
return response.data.status != "init"; 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(){ function GetUser(){
const token = localStorage.getItem('token'); const token = localStorage.getItem('token');
@ -66,5 +85,7 @@ export {
LoadUser, LoadUser,
IsAdmin, IsAdmin,
LogoutUser, LogoutUser,
HasAdmin HasAdmin,
GetUserSetting,
SetUserSetting
} }

View File

@ -36,7 +36,7 @@ const defValues = {
close: () => ClearWindow('edit_profile') close: () => ClearWindow('edit_profile')
}, },
'settings': { 'settings': {
id: 'ettings', id: 'settings',
title: "Dragonroll settings", title: "Dragonroll settings",
close: () => ClearWindow('settings') close: () => ClearWindow('settings')
}, },

View File

@ -1,35 +1,39 @@
<script setup> <script setup>
import { onMounted, ref } from 'vue'; import { onMounted, ref, watch } from 'vue';
import { AddContextMenu } from '../../services/ContextMenu'; import { AddContextMenu, HideContextMenu } from '../../services/ContextMenu';
const props = defineProps(['options', 'selected']); const props = defineProps(['options', 'onselect', 'selected']);
const options = props.options; const options = props.options;
const selected = props.selected; const selectCallback = props.onselect;
const initialSelect = props.selected;
const dropdown = ref(null); const dropdown = ref(null);
const selected = ref(initialSelect);
onMounted(() => { onMounted(() => {
let context = []; let context = [];
items.value.forEach(name => { watch(() => props.selected, () => {
selected.value = props.selected;
});
options.forEach(name => {
context.push({ context.push({
icon: selectedTags.value.includes(name) ? 'icons/iconoir/regular/check.svg' : false, icon: selected.value == name ? 'icons/iconoir/regular/check.svg' : false,
name, name,
action: () => { action: () => {
HideContextMenu(); HideContextMenu();
if(!selectedTags.value.includes(name)){ selected.value = name;
SelectTab(name); selectCallback(name);
} else { RemoveTag(name) }
} }
}); });
}); });
ShowContextMenu(context);
AddContextMenu(dropdown.value); AddContextMenu(dropdown.value, context, {dropdown: true});
}); });
</script> </script>
<template> <template>
<div class="dropdown" ref="dropdown"> <div class="dropdown" ref="dropdown">
<span>Hola</span> <span>{{ selected }}</span>
</div> </div>
</template> </template>

View File

@ -78,9 +78,9 @@ onMounted(() => {
</div> </div>
<div class="main-user-actions"> <div class="main-user-actions">
<button class="btn-primary button-small sound-click" v-on:click.prevent="EditProfile">Edit profile</button> <button class="btn-primary button-small sound-click" v-on:click.prevent="EditProfile">{{ $t("main-menu.edit-profile") }}</button>
<button class="btn-primary button-small sound-click" v-on:click.prevent="EditSettings">Settings</button> <button class="btn-primary button-small sound-click" v-on:click.prevent="EditSettings">{{ $t("main-menu.settings") }}</button>
<button class="btn-primary button-small sound-click" v-on:click.prevent="LogOut">Log out</button> <button class="btn-primary button-small sound-click" v-on:click.prevent="LogOut">{{ $t("main-menu.log-out") }}</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -82,13 +82,13 @@ function OpenBookAnvil(){
<EditUserPartial></EditUserPartial> <EditUserPartial></EditUserPartial>
<h1>{{ $t("main-menu")}}</h1> <h1>{{ $t("main-menu.main-menu")}}</h1>
<div class="button-container"> <div class="button-container">
<button class="btn-primary button-expand sound-click" v-on:click="OpenCampaigns" ref="campaignButton">Campaigns</button> <button class="btn-primary button-expand sound-click" v-on:click="OpenCampaigns" ref="campaignButton">{{ $t("main-menu.campaigns") }}</button>
<hr> <hr>
<button class="btn-primary button-expand sound-click" v-on:click="OpenCompendium">The Cosmic Compendium</button> <button class="btn-primary button-expand sound-click" v-on:click="OpenCompendium">{{ $t("main-menu.cosmic-compendium") }}</button>
<button class="btn-primary button-expand sound-click" v-on:click="OpenBookAnvil">Book Anvil</button> <button class="btn-primary button-expand sound-click" v-on:click="OpenBookAnvil">{{ $t("main-menu.book-anvil") }}</button>
</div> </div>
<VersionRender></VersionRender> <VersionRender></VersionRender>
</div> </div>

View File

@ -5,8 +5,8 @@ import { GetUser } from '@/services/User'
import WindowHandle from '@/views/partials/WindowHandle.vue'; import WindowHandle from '@/views/partials/WindowHandle.vue';
import Tabs from '../partials/Tabs.vue'; import Tabs from '../partials/Tabs.vue';
import { I18nD, I18nN } from 'vue-i18n';
import Dropdown from '../partials/Dropdown.vue'; import Dropdown from '../partials/Dropdown.vue';
import { GetUserSetting, SetUserSetting } from '../../services/User';
const handle = ref(null); const handle = ref(null);
@ -17,20 +17,36 @@ let id = data.id;
let rows = ref(["Account settings"]); let rows = ref(["Account settings"]);
const languageOptions = ref(["English", "Spanish", "Catalan"])
const langSelector = ref(null); const langSelector = ref(null);
const currentLanguage = ref("");
onBeforeMount(() => { 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"); if(GetUser().admin) rows.value.push("Site Administration");
}); });
onMounted(() => { onMounted(() => {
SetupHandle(id, handle); SetupHandle(id, handle);
SetSize(id, {width: 500, height: 380}); SetSize(id, {width: 400, height: 480});
ResetPosition(id, "center"); ResetPosition(id, "center");
}); });
function OnLanguageChange(){ async function OnLanguageChange(value){
I18n.locale = langSelector.value.value; let codes = {
"English": "en",
"Spanish": "es",
"Catalan": "ca"
}
await SetUserSetting("lang", codes[value]);
} }
</script> </script>
@ -42,8 +58,13 @@ function OnLanguageChange(){
<!-- Body --> <!-- Body -->
<Tabs :rows="rows"> <Tabs :rows="rows">
<template #account-settings> <template #account-settings>
Language: <Dropdown :options="languageOptions" :select="OnLanguageChange"></Dropdown> <div class="form-container">
</template> <div class="form-element">
<label>Language: </label>
<Dropdown :options="languageOptions" :onselect="OnLanguageChange" :selected="currentLanguage"></Dropdown>
</div>
</div>
</template>Hola
<template #site-administration> <template #site-administration>
</template> </template>
@ -54,9 +75,6 @@ function OnLanguageChange(){
<style scoped> <style scoped>
.window-wrapper { .window-wrapper {
min-width: 700px;
min-height: 630px;
width: 100%; width: 100%;
display: flex; display: flex;
align-items: center; align-items: center;

View File

@ -108,12 +108,12 @@ function InitValues(){
rarity.value.addEventListener("click", () => { rarity.value.addEventListener("click", () => {
ShowContextMenu(rarities) ShowContextMenu(rarities)
}); });
AddContextMenu(rarity.value, rarities) AddContextMenu(rarity.value, rarities, {dropdown: true})
weaponType.value.addEventListener("click", () => { weaponType.value.addEventListener("click", () => {
ShowContextMenu(weapon_types) ShowContextMenu(weapon_types)
}); });
AddContextMenu(weaponType.value, weapon_types); AddContextMenu(weaponType.value, weapon_types, {dropdown: true});
item_name.value.addEventListener('blur', () => { item_name.value.addEventListener('blur', () => {
concept.value.name = item_name.value.textContent; concept.value.name = item_name.value.textContent;