AQ
This commit is contained in:
parent
aa88bb9802
commit
58c04ec3b9
@ -16,6 +16,11 @@ function hasCampaign(req, res, next){
|
|||||||
}).catch((err) => res.json({status: "error", err}));
|
}).catch((err) => res.json({status: "error", err}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasUser(req, res, next){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
hasCampaign
|
hasCampaign,
|
||||||
|
hasUser
|
||||||
}
|
}
|
@ -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);
|
@ -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;
|
@ -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);
|
||||||
|
@ -276,4 +276,20 @@ 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;
|
||||||
}
|
}
|
3
client/src/locale/ca.json
Normal file
3
client/src/locale/ca.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"main-menu": "Menú Principal"
|
||||||
|
}
|
@ -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"
|
||||||
|
}
|
||||||
}
|
}
|
@ -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"
|
||||||
|
}
|
||||||
}
|
}
|
@ -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
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
@ -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')
|
||||||
},
|
},
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user