Start implementation of branches, new form element tabledropdown, model improvements
@@ -1,13 +1,69 @@
|
|||||||
import * as falukantService from '../services/falukantService.js';
|
import FalukantService from '../services/falukantService.js';
|
||||||
|
|
||||||
class FalukantController {
|
class FalukantController {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.exampleMethod = this.exampleMethod.bind(this);
|
this.getUser = this.getUser.bind(this);
|
||||||
|
this.createUser = this.createUser.bind(this);
|
||||||
|
this.randomFirstName = this.randomFirstName.bind(this);
|
||||||
|
this.randomLastName = this.randomLastName.bind(this);
|
||||||
|
this.getInfo = this.getInfo.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
async exampleMethod(req, res) {
|
async getUser(req, res) {
|
||||||
try {
|
try {
|
||||||
const result = await falukantService.exampleMethod();
|
const { userid: hashedUserId } = req.headers;
|
||||||
|
const result = await FalukantService.getUser(hashedUserId);
|
||||||
|
res.status(200).json(result);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ error: error.message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async createUser(req, res) {
|
||||||
|
try {
|
||||||
|
const { userid: hashedUserId } = req.headers;
|
||||||
|
const { gender, firstname: firstName, lastname: lastName } = req.body;
|
||||||
|
console.log(req.body);
|
||||||
|
const result = await FalukantService.createUser(hashedUserId, gender, firstName, lastName);
|
||||||
|
res.status(201).json(result);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ error: error.message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async randomFirstName(req, res) {
|
||||||
|
try {
|
||||||
|
const { gender } = req.params;
|
||||||
|
const result = await FalukantService.randomFirstName(gender);
|
||||||
|
res.status(200).json({ name: result });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ error: error.message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async randomLastName(req, res) {
|
||||||
|
try {
|
||||||
|
const result = await FalukantService.randomLastName();
|
||||||
|
res.status(200).json({ name: result });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ error: error.message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getInfo(req, res) {
|
||||||
|
try {
|
||||||
|
const { userid: hashedUserId } = req.headers;
|
||||||
|
const result = await FalukantService.getInfo(hashedUserId);
|
||||||
|
res.status(200).json(result);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ error: error.message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getBranches(req, res) {
|
||||||
|
try {
|
||||||
|
const { userid: hashedUserId } = req.headers;
|
||||||
|
const result = await FalukantService.getBranches(hashedUserId);
|
||||||
res.status(200).json(result);
|
res.status(200).json(result);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.status(500).json({ error: error.message });
|
res.status(500).json({ error: error.message });
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ const menuStructure = {
|
|||||||
},
|
},
|
||||||
towns: {
|
towns: {
|
||||||
visible: ["hasfalukantaccount"],
|
visible: ["hasfalukantaccount"],
|
||||||
path: "/falukant/towns"
|
path: "/falukant/branch"
|
||||||
},
|
},
|
||||||
directors: {
|
directors: {
|
||||||
visible: ["hasfalukantaccount"],
|
visible: ["hasfalukantaccount"],
|
||||||
@@ -117,6 +117,10 @@ const menuStructure = {
|
|||||||
visible: ["hasfalukantaccount"],
|
visible: ["hasfalukantaccount"],
|
||||||
path: "/falukant/education"
|
path: "/falukant/education"
|
||||||
},
|
},
|
||||||
|
health: {
|
||||||
|
visible: ["hasfalukantaccount"],
|
||||||
|
path: "/falukant/health"
|
||||||
|
},
|
||||||
bank: {
|
bank: {
|
||||||
visible: ["hasfalukantaccount"],
|
visible: ["hasfalukantaccount"],
|
||||||
path: "/falukant/bank"
|
path: "/falukant/bank"
|
||||||
@@ -238,7 +242,6 @@ class NavigationController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async filterMenu(menu, rights, age, userId) {
|
async filterMenu(menu, rights, age, userId) {
|
||||||
console.log(userId);
|
|
||||||
const filteredMenu = {};
|
const filteredMenu = {};
|
||||||
const hasFalukantAccount = await this.hasFalukantAccount(userId);
|
const hasFalukantAccount = await this.hasFalukantAccount(userId);
|
||||||
for (const [key, value] of Object.entries(menu)) {
|
for (const [key, value] of Object.entries(menu)) {
|
||||||
|
|||||||
@@ -31,6 +31,18 @@ import Friendship from './community/friendship.js';
|
|||||||
import FalukantUser from './falukant/data/user.js';
|
import FalukantUser from './falukant/data/user.js';
|
||||||
import RegionType from './falukant/type/region.js';
|
import RegionType from './falukant/type/region.js';
|
||||||
import RegionData from './falukant/data/region.js';
|
import RegionData from './falukant/data/region.js';
|
||||||
|
import FalukantCharacter from './falukant/data/character.js';
|
||||||
|
import FalukantPredefineFirstname from './falukant/predefine/firstname.js';
|
||||||
|
import FalukantPredefineLastname from './falukant/predefine/lastname.js';
|
||||||
|
import FalukantStock from './falukant/data/stock.js';
|
||||||
|
import FalukantStockType from './falukant/type/stock.js';
|
||||||
|
import Knowledge from './falukant/data/product_knowledge.js';
|
||||||
|
import ProductType from './falukant/type/product.js';
|
||||||
|
import TitleOfNobility from './falukant/type/title_of_nobility.js';
|
||||||
|
import TitleRequirement from './falukant/type/title_requirement.js';
|
||||||
|
import Branch from './falukant/data/branch.js';
|
||||||
|
import BranchType from './falukant/type/branch.js';
|
||||||
|
|
||||||
|
|
||||||
export default function setupAssociations() {
|
export default function setupAssociations() {
|
||||||
// UserParam related associations
|
// UserParam related associations
|
||||||
@@ -181,4 +193,46 @@ export default function setupAssociations() {
|
|||||||
|
|
||||||
FalukantUser.belongsTo(RegionData, { foreignKey: 'mainBranchRegionId', as: 'mainBranchRegion' });
|
FalukantUser.belongsTo(RegionData, { foreignKey: 'mainBranchRegionId', as: 'mainBranchRegion' });
|
||||||
RegionData.hasMany(FalukantUser, { foreignKey: 'mainBranchRegionId', as: 'users' });
|
RegionData.hasMany(FalukantUser, { foreignKey: 'mainBranchRegionId', as: 'users' });
|
||||||
|
|
||||||
|
FalukantCharacter.belongsTo(FalukantUser, { foreignKey: 'userId', as: 'user' });
|
||||||
|
FalukantUser.hasOne(FalukantCharacter, { foreignKey: 'userId', as: 'character' });
|
||||||
|
|
||||||
|
FalukantCharacter.belongsTo(FalukantPredefineFirstname, { foreignKey: 'firstName', as: 'definedFirstName' });
|
||||||
|
FalukantPredefineFirstname.hasMany(FalukantCharacter, { foreignKey: 'firstName', as: 'charactersWithFirstName' });
|
||||||
|
|
||||||
|
FalukantCharacter.belongsTo(FalukantPredefineLastname, { foreignKey: 'lastName', as: 'definedLastName' });
|
||||||
|
FalukantPredefineLastname.hasMany(FalukantCharacter, { foreignKey: 'lastName', as: 'charactersWithLastName' });
|
||||||
|
|
||||||
|
FalukantCharacter.belongsTo(TitleOfNobility, { foreignKey: 'titleOfNobility', as: 'nobleTitle' });
|
||||||
|
TitleOfNobility.hasMany(FalukantCharacter, { foreignKey: 'titleOfNobility', as: 'charactersWithNobleTitle' });
|
||||||
|
|
||||||
|
FalukantCharacter.belongsTo(RegionData, { foreignKey: 'regionId', as: 'region' });
|
||||||
|
RegionData.hasMany(FalukantCharacter, { foreignKey: 'regionId', as: 'charactersInRegion' });
|
||||||
|
|
||||||
|
FalukantStock.belongsTo(FalukantStockType, { foreignKey: 'stockTypeId', as: 'stockType' });
|
||||||
|
FalukantStockType.hasMany(FalukantStock, { foreignKey: 'stockTypeId', as: 'stocks' });
|
||||||
|
|
||||||
|
FalukantStock.belongsTo(FalukantUser, { foreignKey: 'userId', as: 'user' });
|
||||||
|
FalukantUser.hasMany(FalukantStock, { foreignKey: 'userId', as: 'stocks' });
|
||||||
|
|
||||||
|
FalukantStock.belongsTo(RegionData, { foreignKey: 'regionId', as: 'region' });
|
||||||
|
RegionData.hasMany(FalukantStock, { foreignKey: 'regionId', as: 'stocksInRegion' });
|
||||||
|
|
||||||
|
Knowledge.belongsTo(ProductType, { foreignKey: 'productTypeId', as: 'productType' });
|
||||||
|
ProductType.hasMany(Knowledge, { foreignKey: 'productTypeId', as: 'knowledges' });
|
||||||
|
|
||||||
|
Knowledge.belongsTo(FalukantCharacter, { foreignKey: 'characterId', as: 'character' });
|
||||||
|
FalukantCharacter.hasMany(Knowledge, { foreignKey: 'characterId', as: 'knowledges' });
|
||||||
|
|
||||||
|
TitleRequirement.belongsTo(TitleOfNobility, { foreignKey: 'titleId', as: 'title' });
|
||||||
|
TitleOfNobility.hasMany(TitleRequirement, { foreignKey: 'titleId', as: 'requirements' });
|
||||||
|
|
||||||
|
Branch.belongsTo(RegionData, { foreignKey: 'regionId', as: 'region' });
|
||||||
|
RegionData.hasMany(Branch, { foreignKey: 'regionId', as: 'branches' });
|
||||||
|
|
||||||
|
Branch.belongsTo(FalukantUser, { foreignKey: 'falukantUserId', as: 'user' });
|
||||||
|
FalukantUser.hasMany(Branch, { foreignKey: 'falukantUserId', as: 'branches' });
|
||||||
|
|
||||||
|
Branch.belongsTo(BranchType, { foreignKey: 'branchTypeId', as: 'branchType' });
|
||||||
|
BranchType.hasMany(Branch, { foreignKey: 'branchTypeId', as: 'branches' });
|
||||||
}
|
}
|
||||||
|
|||||||
34
backend/models/falukant/data/branch.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { Model, DataTypes } from 'sequelize';
|
||||||
|
import { sequelize } from '../../../utils/sequelize.js';
|
||||||
|
|
||||||
|
class Branch extends Model { }
|
||||||
|
|
||||||
|
Branch.init({
|
||||||
|
branchTypeId: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
regionId: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
falukantUserId: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
sequelize,
|
||||||
|
modelName: 'BranchType',
|
||||||
|
tableName: 'branch',
|
||||||
|
schema: 'falukant_data',
|
||||||
|
timestamps: false,
|
||||||
|
underscored: true,
|
||||||
|
indexes: [
|
||||||
|
{
|
||||||
|
unique: true,
|
||||||
|
fields: ['region_id', 'falukant_user_id']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
export default Branch;
|
||||||
49
backend/models/falukant/data/character.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import { Model, DataTypes } from 'sequelize';
|
||||||
|
import { sequelize } from '../../../utils/sequelize.js';
|
||||||
|
|
||||||
|
class FalukantCharacter extends Model {};
|
||||||
|
|
||||||
|
FalukantCharacter.init({
|
||||||
|
userId: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: true,
|
||||||
|
},
|
||||||
|
regionId: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
firstName: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
lastName: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
birthdate: {
|
||||||
|
type: DataTypes.DATE,
|
||||||
|
allowNull: false,
|
||||||
|
defaultValue: DataTypes.NOW
|
||||||
|
},
|
||||||
|
gender: {
|
||||||
|
type: DataTypes.STRING
|
||||||
|
},
|
||||||
|
health: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
defaultValue: 100
|
||||||
|
},
|
||||||
|
titleOfNobility: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
sequelize,
|
||||||
|
modelName: 'FalukantCharacter',
|
||||||
|
tableName: 'character',
|
||||||
|
schema: 'falukant_data',
|
||||||
|
timestamps: true,
|
||||||
|
underscored: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default FalukantCharacter;
|
||||||
34
backend/models/falukant/data/product_knowledge.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { Model, DataTypes } from 'sequelize';
|
||||||
|
import { sequelize } from '../../../utils/sequelize.js';
|
||||||
|
|
||||||
|
class Knowledge extends Model { }
|
||||||
|
|
||||||
|
Knowledge.init({
|
||||||
|
productId: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
characterId: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
knowledge: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
defaultValue: 0,
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
sequelize,
|
||||||
|
modelName: 'Knowledge',
|
||||||
|
tableName: 'knowledge',
|
||||||
|
schema: 'falukant_data',
|
||||||
|
timestamps: false,
|
||||||
|
underscored: true,
|
||||||
|
hooks: {
|
||||||
|
beforeCreate: (knowledge) => {
|
||||||
|
knowledge.knowledge = Math.floor(Math.random() * 61) + 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default Knowledge;
|
||||||
32
backend/models/falukant/data/stock.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { Model, DataTypes } from 'sequelize';
|
||||||
|
import { sequelize } from '../../../utils/sequelize.js';
|
||||||
|
|
||||||
|
class FalukantStock extends Model { }
|
||||||
|
|
||||||
|
FalukantStock.init({
|
||||||
|
userId: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
regionId: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
stockTypeId: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
quantity: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
sequelize,
|
||||||
|
modelName: 'StockType',
|
||||||
|
tableName: 'stock',
|
||||||
|
schema: 'falukant_data',
|
||||||
|
timestamps: false,
|
||||||
|
underscored: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default FalukantStock;
|
||||||
@@ -14,7 +14,8 @@ FalukantUser.init({
|
|||||||
schema: 'community'
|
schema: 'community'
|
||||||
},
|
},
|
||||||
key: 'id'
|
key: 'id'
|
||||||
}
|
},
|
||||||
|
unique: true,
|
||||||
},
|
},
|
||||||
money: {
|
money: {
|
||||||
type: DataTypes.DECIMAL(10, 2),
|
type: DataTypes.DECIMAL(10, 2),
|
||||||
|
|||||||
26
backend/models/falukant/predefine/firstname.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { sequelize } from '../../../utils/sequelize.js';
|
||||||
|
import { DataTypes } from 'sequelize';
|
||||||
|
|
||||||
|
const FalukantPredefineFirstname = sequelize.define('firstname', {
|
||||||
|
name: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false
|
||||||
|
},
|
||||||
|
gender: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
tableName: 'firstname',
|
||||||
|
schema: 'falukant_predefine',
|
||||||
|
underscored: true,
|
||||||
|
timestamps: false,
|
||||||
|
indexes: [
|
||||||
|
{
|
||||||
|
unique: true,
|
||||||
|
fields: ['name', 'gender']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
export default FalukantPredefineFirstname;
|
||||||
23
backend/models/falukant/predefine/lastname.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { sequelize } from '../../../utils/sequelize.js';
|
||||||
|
import { DataTypes } from 'sequelize';
|
||||||
|
|
||||||
|
const FalukantPredefineLastname = sequelize.define('lastname', {
|
||||||
|
name: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
length: 1,
|
||||||
|
allowNull: false
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
tableName: 'lastname',
|
||||||
|
schema: 'falukant_predefine',
|
||||||
|
underscored: true,
|
||||||
|
timestamps: false,
|
||||||
|
indexes: [
|
||||||
|
{
|
||||||
|
unique: true,
|
||||||
|
fields: ['name']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
export default FalukantPredefineLastname;
|
||||||
30
backend/models/falukant/type/branch.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { Model, DataTypes } from 'sequelize';
|
||||||
|
import { sequelize } from '../../../utils/sequelize.js';
|
||||||
|
|
||||||
|
class BranchType extends Model { }
|
||||||
|
|
||||||
|
BranchType.init({
|
||||||
|
labelTr: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
baseCost: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
sequelize,
|
||||||
|
modelName: 'BranchType',
|
||||||
|
tableName: 'branch',
|
||||||
|
schema: 'falukant_type',
|
||||||
|
timestamps: false,
|
||||||
|
underscored: true,
|
||||||
|
indexes: [
|
||||||
|
{
|
||||||
|
unique: true,
|
||||||
|
fields: ['label_tr']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
export default BranchType;
|
||||||
38
backend/models/falukant/type/product.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { Model, DataTypes } from 'sequelize';
|
||||||
|
import { sequelize } from '../../../utils/sequelize.js';
|
||||||
|
|
||||||
|
class ProductType extends Model { }
|
||||||
|
|
||||||
|
ProductType.init({
|
||||||
|
labelTr: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
category: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
productionTime: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
sellCost: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
sequelize,
|
||||||
|
modelName: 'ProductType',
|
||||||
|
tableName: 'product',
|
||||||
|
schema: 'falukant_type',
|
||||||
|
timestamps: false,
|
||||||
|
underscored: true,
|
||||||
|
indexes: [
|
||||||
|
{
|
||||||
|
unique: true,
|
||||||
|
fields: ['label_tr']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
export default ProductType;
|
||||||
24
backend/models/falukant/type/stock.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { Model, DataTypes } from 'sequelize';
|
||||||
|
import { sequelize } from '../../../utils/sequelize.js';
|
||||||
|
|
||||||
|
class FalukantStockType extends Model { }
|
||||||
|
|
||||||
|
FalukantStockType.init({
|
||||||
|
labelTr: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
cost: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
sequelize,
|
||||||
|
modelName: 'StockType',
|
||||||
|
tableName: 'stock',
|
||||||
|
schema: 'falukant_type',
|
||||||
|
timestamps: false,
|
||||||
|
underscored: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default FalukantStockType;
|
||||||
20
backend/models/falukant/type/title_of_nobility.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { Model, DataTypes } from 'sequelize';
|
||||||
|
import { sequelize } from '../../../utils/sequelize.js';
|
||||||
|
|
||||||
|
class TitleOfNobility extends Model { }
|
||||||
|
|
||||||
|
TitleOfNobility.init({
|
||||||
|
labelTr: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
sequelize,
|
||||||
|
modelName: 'Title',
|
||||||
|
tableName: 'title',
|
||||||
|
schema: 'falukant_type',
|
||||||
|
timestamps: false,
|
||||||
|
underscored: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default TitleOfNobility;
|
||||||
30
backend/models/falukant/type/title_requirement.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { Model, DataTypes } from 'sequelize';
|
||||||
|
import { sequelize } from '../../../utils/sequelize.js';
|
||||||
|
|
||||||
|
class TitleRequirement extends Model { }
|
||||||
|
|
||||||
|
TitleRequirement.init({
|
||||||
|
titleId: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
primaryKey: true,
|
||||||
|
autoIncrement: true,
|
||||||
|
},
|
||||||
|
requirementType: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
requirementValue: {
|
||||||
|
type: DataTypes.DECIMAL(14, 2),
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
sequelize,
|
||||||
|
modelName: 'TitleRequirement',
|
||||||
|
tableName: 'title_requirement',
|
||||||
|
schema: 'falukant_type',
|
||||||
|
timestamps: false,
|
||||||
|
underscored: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default TitleRequirement;
|
||||||
@@ -35,6 +35,17 @@ import Friendship from './community/friendship.js';
|
|||||||
import FalukantUser from './falukant/data/user.js';
|
import FalukantUser from './falukant/data/user.js';
|
||||||
import RegionType from './falukant/type/region.js';
|
import RegionType from './falukant/type/region.js';
|
||||||
import RegionData from './falukant/data/region.js';
|
import RegionData from './falukant/data/region.js';
|
||||||
|
import FalukantPredefineFirstname from './falukant/predefine/firstname.js';
|
||||||
|
import FalukantPredefineLastname from './falukant/predefine/lastname.js';
|
||||||
|
import FalukantCharacter from './falukant/data/character.js';
|
||||||
|
import FalukantStock from './falukant/data/stock.js';
|
||||||
|
import FalukantStockType from './falukant/type/stock.js';
|
||||||
|
import ProductType from './falukant/type/product.js';
|
||||||
|
import Knowledge from './falukant/data/product_knowledge.js';
|
||||||
|
import TitleRequirement from './falukant/type/title_requirement.js';
|
||||||
|
import TitleOfNobility from './falukant/type/title_of_nobility.js';
|
||||||
|
import BranchType from './falukant/type/branch.js';
|
||||||
|
import Branch from './falukant/data/branch.js';
|
||||||
|
|
||||||
const models = {
|
const models = {
|
||||||
SettingsType,
|
SettingsType,
|
||||||
@@ -74,6 +85,17 @@ const models = {
|
|||||||
RegionType,
|
RegionType,
|
||||||
RegionData,
|
RegionData,
|
||||||
FalukantUser,
|
FalukantUser,
|
||||||
|
FalukantPredefineFirstname,
|
||||||
|
FalukantPredefineLastname,
|
||||||
|
FalukantCharacter,
|
||||||
|
FalukantStock,
|
||||||
|
FalukantStockType,
|
||||||
|
ProductType,
|
||||||
|
Knowledge,
|
||||||
|
TitleOfNobility,
|
||||||
|
TitleRequirement,
|
||||||
|
BranchType,
|
||||||
|
Branch,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default models;
|
export default models;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { sequelize } from '../utils/sequelize.js';
|
|||||||
|
|
||||||
export async function createTriggers() {
|
export async function createTriggers() {
|
||||||
const createTriggerFunction = `
|
const createTriggerFunction = `
|
||||||
CREATE OR REPLACE FUNCTION create_user_param_visibility_trigger()
|
CREATE OR REPLACE FUNCTION community.create_user_param_visibility_trigger()
|
||||||
RETURNS TRIGGER AS $$
|
RETURNS TRIGGER AS $$
|
||||||
BEGIN
|
BEGIN
|
||||||
-- Check if UserParamVisibility already exists for this UserParam
|
-- Check if UserParamVisibility already exists for this UserParam
|
||||||
@@ -32,7 +32,7 @@ export async function createTriggers() {
|
|||||||
AFTER INSERT ON community.user_param
|
AFTER INSERT ON community.user_param
|
||||||
FOR EACH ROW
|
FOR EACH ROW
|
||||||
WHEN (NEW.id IS NOT NULL)
|
WHEN (NEW.id IS NOT NULL)
|
||||||
EXECUTE FUNCTION create_user_param_visibility_trigger();
|
EXECUTE FUNCTION community.create_user_param_visibility_trigger();
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const createUpdateTrigger = `
|
const createUpdateTrigger = `
|
||||||
@@ -40,11 +40,11 @@ export async function createTriggers() {
|
|||||||
AFTER UPDATE ON community.user_param
|
AFTER UPDATE ON community.user_param
|
||||||
FOR EACH ROW
|
FOR EACH ROW
|
||||||
WHEN (NEW.id IS NOT NULL)
|
WHEN (NEW.id IS NOT NULL)
|
||||||
EXECUTE FUNCTION create_user_param_visibility_trigger();
|
EXECUTE FUNCTION community.create_user_param_visibility_trigger();
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const createDiaryHistoryTriggerFunction = `
|
const createDiaryHistoryTriggerFunction = `
|
||||||
CREATE OR REPLACE FUNCTION insert_diary_history()
|
CREATE OR REPLACE FUNCTION community.insert_diary_history()
|
||||||
RETURNS TRIGGER AS $$
|
RETURNS TRIGGER AS $$
|
||||||
BEGIN
|
BEGIN
|
||||||
INSERT INTO community.diary_history (diary_id, user_id, old_text, old_created_at, old_updated_at)
|
INSERT INTO community.diary_history (diary_id, user_id, old_text, old_created_at, old_updated_at)
|
||||||
@@ -65,11 +65,11 @@ export async function createTriggers() {
|
|||||||
BEFORE UPDATE ON community.diary
|
BEFORE UPDATE ON community.diary
|
||||||
FOR EACH ROW
|
FOR EACH ROW
|
||||||
WHEN (OLD.id IS NOT NULL)
|
WHEN (OLD.id IS NOT NULL)
|
||||||
EXECUTE FUNCTION insert_diary_history();
|
EXECUTE FUNCTION community.insert_diary_history();
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const createTitleHistoryTriggerFunction = `
|
const createTitleHistoryTriggerFunction = `
|
||||||
CREATE OR REPLACE FUNCTION insert_title_history()
|
CREATE OR REPLACE FUNCTION forum.insert_title_history()
|
||||||
RETURNS TRIGGER AS $$
|
RETURNS TRIGGER AS $$
|
||||||
BEGIN
|
BEGIN
|
||||||
INSERT INTO forum.title_history (title_id, old_title, changed_by, old_updated_at)
|
INSERT INTO forum.title_history (title_id, old_title, changed_by, old_updated_at)
|
||||||
@@ -84,7 +84,44 @@ export async function createTriggers() {
|
|||||||
BEFORE UPDATE ON forum.title
|
BEFORE UPDATE ON forum.title
|
||||||
FOR EACH ROW
|
FOR EACH ROW
|
||||||
WHEN (OLD.id IS NOT NULL)
|
WHEN (OLD.id IS NOT NULL)
|
||||||
EXECUTE FUNCTION insert_title_history();
|
EXECUTE FUNCTION forum.insert_title_history();
|
||||||
|
`;
|
||||||
|
|
||||||
|
const createCharacterCreationTriggerMethod = `
|
||||||
|
CREATE OR REPLACE FUNCTION falukant_data.create_character_creation_trigger()
|
||||||
|
RETURNS TRIGGER AS $$
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO falukant_data.knowledge (product_id, character_id)
|
||||||
|
SELECT id, NEW.id FROM falukant_type.product;
|
||||||
|
RETURN NEW;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const createCharacterCreationTrigger = `
|
||||||
|
CREATE OR REPLACE TRIGGER character_creation_trigger
|
||||||
|
AFTER INSERT ON falukant_data.character
|
||||||
|
FOR EACH ROW
|
||||||
|
WHEN (NEW.id IS NOT NULL)
|
||||||
|
EXECUTE FUNCTION falukant_data.create_character_creation_trigger();
|
||||||
|
`;
|
||||||
|
|
||||||
|
const createKnowledgeTriggerMethod = `
|
||||||
|
CREATE OR REPLACE FUNCTION falukant_data.create_knowledge_trigger()
|
||||||
|
RETURNS TRIGGER AS $$
|
||||||
|
BEGIN
|
||||||
|
NEW.knowledge = random() * 61 + 20;
|
||||||
|
RETURN NEW;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const createKnowledgeTrigger = `
|
||||||
|
CREATE OR REPLACE TRIGGER knowledge_trigger
|
||||||
|
BEFORE INSERT ON falukant_data.knowledge
|
||||||
|
FOR EACH ROW
|
||||||
|
WHEN (NEW.id IS NOT NULL)
|
||||||
|
EXECUTE FUNCTION falukant_data.create_knowledge_trigger();
|
||||||
`;
|
`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -95,10 +132,14 @@ export async function createTriggers() {
|
|||||||
await sequelize.query(createDiaryHistoryTrigger);
|
await sequelize.query(createDiaryHistoryTrigger);
|
||||||
await sequelize.query(createTitleHistoryTriggerFunction);
|
await sequelize.query(createTitleHistoryTriggerFunction);
|
||||||
await sequelize.query(createTitleHistoryTrigger);
|
await sequelize.query(createTitleHistoryTrigger);
|
||||||
|
await sequelize.query(createCharacterCreationTriggerMethod);
|
||||||
|
await sequelize.query(createCharacterCreationTrigger);
|
||||||
|
await sequelize.query(createKnowledgeTriggerMethod);
|
||||||
|
await sequelize.query(createKnowledgeTrigger);
|
||||||
|
|
||||||
console.log('Triggers created successfully');
|
console.log('Triggers created successfully');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error creating triggers:', error);
|
console.error('Error creating triggers:', error);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
16
backend/package-lock.json
generated
@@ -13,6 +13,7 @@
|
|||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
"connect-redis": "^7.1.1",
|
"connect-redis": "^7.1.1",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
|
"date-fns": "^4.1.0",
|
||||||
"dompurify": "^3.1.7",
|
"dompurify": "^3.1.7",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"express": "^4.19.2",
|
"express": "^4.19.2",
|
||||||
@@ -1231,9 +1232,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/cross-spawn": {
|
"node_modules/cross-spawn": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||||
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"path-key": "^3.1.0",
|
"path-key": "^3.1.0",
|
||||||
@@ -1311,6 +1312,15 @@
|
|||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/date-fns": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/kossnocorp"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.3.5",
|
"version": "4.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
"connect-redis": "^7.1.1",
|
"connect-redis": "^7.1.1",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
|
"date-fns": "^4.1.0",
|
||||||
"dompurify": "^3.1.7",
|
"dompurify": "^3.1.7",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"express": "^4.19.2",
|
"express": "^4.19.2",
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ import FalukantController from '../controllers/falukantController.js';
|
|||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const falukantController = new FalukantController();
|
const falukantController = new FalukantController();
|
||||||
|
|
||||||
router.get('/example', falukantController.exampleMethod);
|
router.get('/user', falukantController.getUser);
|
||||||
|
router.post('/user', falukantController.createUser);
|
||||||
|
router.get('/name/randomfirstname/:gender', falukantController.randomFirstName);
|
||||||
|
router.get('/name/randomlastname', falukantController.randomLastName);
|
||||||
|
router.get('/info', falukantController.getInfo);
|
||||||
|
router.get('/branches', falukantController.getBranches);
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
@@ -1,7 +1,284 @@
|
|||||||
class FalukantService {
|
import BaseService from './BaseService.js';
|
||||||
async exampleMethod() {
|
import FalukantPredefineFirstname from '../models/falukant/predefine/firstname.js';
|
||||||
// Logik für die Methode
|
import FalukantPredefineLastname from '../models/falukant/predefine/lastname.js';
|
||||||
|
import FalukantUser from '../models/falukant/data/user.js';
|
||||||
|
import User from '../models/community/user.js';
|
||||||
|
import FalukantCharacter from '../models/falukant/data/character.js';
|
||||||
|
import RegionData from '../models/falukant/data/region.js';
|
||||||
|
import RegionType from '../models/falukant/type/region.js';
|
||||||
|
import { Sequelize } from 'sequelize';
|
||||||
|
import FalukantStock from '../models/falukant/data/stock.js';
|
||||||
|
import FalukantStockType from '../models/falukant/type/stock.js';
|
||||||
|
import { notifyUser } from '../utils/socket.js';
|
||||||
|
import { differenceInDays } from 'date-fns';
|
||||||
|
import TitleOfNobility from '../models/falukant/type/title_of_nobility.js';
|
||||||
|
import Branch from '../models/falukant/data/branch.js';
|
||||||
|
import BranchType from '../models/falukant/type/branch.js';
|
||||||
|
|
||||||
|
class FalukantService extends BaseService {
|
||||||
|
async getFalukantUserByHashedId(hashedId) {
|
||||||
|
const falukantUser = await FalukantUser.findOne({
|
||||||
|
include: [{
|
||||||
|
model: User,
|
||||||
|
as: 'user',
|
||||||
|
attributes: ['username', 'hashedId'],
|
||||||
|
where: {
|
||||||
|
hashedId: hashedId
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
});
|
||||||
|
return falukantUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getUser(hashedUserId) {
|
||||||
|
const falukantUser = await FalukantUser.findOne({
|
||||||
|
include: [{
|
||||||
|
model: User,
|
||||||
|
as: 'user',
|
||||||
|
attributes: ['username', 'hashedId'],
|
||||||
|
where: {
|
||||||
|
hashedId: hashedUserId
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: FalukantCharacter,
|
||||||
|
as: 'character',
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: FalukantPredefineFirstname,
|
||||||
|
as: 'definedFirstName',
|
||||||
|
attributes: ['name']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: FalukantPredefineLastname,
|
||||||
|
as: 'definedLastName',
|
||||||
|
attributes: ['name']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: TitleOfNobility,
|
||||||
|
as: 'nobleTitle',
|
||||||
|
attributes: ['labelTr']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
attributes: ['birthdate', 'gender'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: RegionData,
|
||||||
|
as: 'mainBranchRegion',
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: RegionType,
|
||||||
|
as: 'regionType',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
attributes: ['name'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: Branch,
|
||||||
|
as: 'branches',
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: BranchType,
|
||||||
|
as: 'branchType',
|
||||||
|
attributes: ['labelTr']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: RegionData,
|
||||||
|
as: 'region',
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: RegionType,
|
||||||
|
as: 'regionType',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
attributes: ['name'],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
attributes: ['money', 'creditAmount', 'todayCreditTaken'],
|
||||||
|
});
|
||||||
|
if (!falukantUser) {
|
||||||
|
throw new Error('User not found');
|
||||||
|
}
|
||||||
|
const character = falukantUser.character;
|
||||||
|
if (character && character.birthdate) {
|
||||||
|
const birthdate = new Date(character.birthdate);
|
||||||
|
birthdate.setHours(0);
|
||||||
|
birthdate.setMinutes(0);
|
||||||
|
const currentDate = new Date();
|
||||||
|
currentDate.setHours(0);
|
||||||
|
currentDate.setMinutes(0);
|
||||||
|
const ageInDays = differenceInDays(currentDate, birthdate);
|
||||||
|
character.setDataValue('age', ageInDays);
|
||||||
|
}
|
||||||
|
return falukantUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
async randomFirstName(gender) {
|
||||||
|
const names = await FalukantPredefineFirstname.findAll({ where: { gender: gender } });
|
||||||
|
return names[Math.floor(Math.random() * names.length)].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
async randomLastName() {
|
||||||
|
const names = await FalukantPredefineLastname.findAll();
|
||||||
|
return names[Math.floor(Math.random() * names.length)].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
async createUser(hashedUserId, gender, firstName, lastName) {
|
||||||
|
try {
|
||||||
|
const user = await this.getUserByHashedId(hashedUserId);
|
||||||
|
const userExistsCheck = await FalukantUser.findOne({ where: { userId: user.id } });
|
||||||
|
if (userExistsCheck) {
|
||||||
|
throw new Error('User already exists in Falukant.');
|
||||||
|
}
|
||||||
|
let firstNameObject = await FalukantPredefineFirstname.findOne({ where: { name: firstName } });
|
||||||
|
let lastNameObject = await FalukantPredefineLastname.findOne({ where: { name: lastName } });
|
||||||
|
if (!firstNameObject) {
|
||||||
|
firstNameObject = await FalukantPredefineFirstname.create({ name: firstName, gender: gender });
|
||||||
|
}
|
||||||
|
if (!lastNameObject) {
|
||||||
|
lastNameObject = await FalukantPredefineLastname.create({ name: lastName });
|
||||||
|
}
|
||||||
|
const randomRegion = await RegionData.findOne({
|
||||||
|
order: Sequelize.fn('RANDOM'),
|
||||||
|
limit: 1,
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: RegionType,
|
||||||
|
as: 'regionType',
|
||||||
|
where: {
|
||||||
|
labelTr: 'city'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
if (!randomRegion) {
|
||||||
|
throw new Error('No region found with the label "city".');
|
||||||
|
}
|
||||||
|
const titleOfNobility = await TitleOfNobility.findOne({ where: { labelTr: 'noncivil' } });
|
||||||
|
if (!titleOfNobility) {
|
||||||
|
throw new Error('No title of nobility found with the label "noncivil".');
|
||||||
|
}
|
||||||
|
const falukantUser = await FalukantUser.create({
|
||||||
|
userId: user.id,
|
||||||
|
money: 50.00,
|
||||||
|
creditAmount: 0.00,
|
||||||
|
todayCreditTaken: 0.00,
|
||||||
|
creditInterestRate: 0.00,
|
||||||
|
mainBranchRegionId: randomRegion.id,
|
||||||
|
});
|
||||||
|
const fourteenDaysAgo = new Date();
|
||||||
|
fourteenDaysAgo.setDate(fourteenDaysAgo.getDate() - 14);
|
||||||
|
const character = await FalukantCharacter.create({
|
||||||
|
userId: falukantUser.id,
|
||||||
|
regionId: randomRegion.id,
|
||||||
|
firstName: firstNameObject.id,
|
||||||
|
lastName: lastNameObject.id,
|
||||||
|
gender: gender,
|
||||||
|
birthdate: fourteenDaysAgo,
|
||||||
|
titleOfNobility: titleOfNobility.id,
|
||||||
|
});
|
||||||
|
await FalukantStock.create({
|
||||||
|
userId: falukantUser.id,
|
||||||
|
regionId: randomRegion.id,
|
||||||
|
stockTypeId: (await FalukantStockType.findOne({ where: [{ label_tr: 'wood' }] })).id,
|
||||||
|
quantity: 10,
|
||||||
|
});
|
||||||
|
falukantUser['character'] = character;
|
||||||
|
const branchType = await BranchType.findOne({ where: { labelTr: 'fullstack' } });
|
||||||
|
await Branch.create({
|
||||||
|
userId: falukantUser.id,
|
||||||
|
regionId: randomRegion.id,
|
||||||
|
branchTypeId: branchType.id,
|
||||||
|
})
|
||||||
|
notifyUser(user.hashedId, 'reloadmenu', {});
|
||||||
|
return falukantUser;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error creating character');
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getInfo(hashedUserId) {
|
||||||
|
try {
|
||||||
|
const user = await User.findOne({ where: { hashedId: hashedUserId } });
|
||||||
|
if (!user) {
|
||||||
|
throw new Error('User not found');
|
||||||
|
}
|
||||||
|
const falukantUser = await FalukantUser.findOne({
|
||||||
|
include: [{
|
||||||
|
model: User,
|
||||||
|
as: 'user',
|
||||||
|
attributes: ['hashedId'],
|
||||||
|
where: {
|
||||||
|
hashedId: hashedUserId
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: FalukantCharacter,
|
||||||
|
as: 'character',
|
||||||
|
attributes: ['birthdate', 'health'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
attributes: ['money']
|
||||||
|
});
|
||||||
|
if (!falukantUser) {
|
||||||
|
throw new Error('User not found');
|
||||||
|
}
|
||||||
|
const character = falukantUser.character;
|
||||||
|
if (character && character.birthdate) {
|
||||||
|
const birthdate = new Date(character.birthdate);
|
||||||
|
birthdate.setHours(0);
|
||||||
|
birthdate.setMinutes(0);
|
||||||
|
const currentDate = new Date();
|
||||||
|
currentDate.setHours(0);
|
||||||
|
currentDate.setMinutes(0);
|
||||||
|
const ageInDays = differenceInDays(currentDate, birthdate);
|
||||||
|
character.setDataValue('age', ageInDays);
|
||||||
|
}
|
||||||
|
return falukantUser;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error getting character info');
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getBranches(hashedUserId) {
|
||||||
|
try {
|
||||||
|
const falukantUser = await this.getFalukantUserByHashedId(hashedUserId);
|
||||||
|
if (!falukantUser) {
|
||||||
|
throw new Error('User not found');
|
||||||
|
}
|
||||||
|
const branches = await Branch.findAll({
|
||||||
|
where: { falukantUserId: falukantUser.id },
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: BranchType,
|
||||||
|
as: 'branchType',
|
||||||
|
attributes: ['labelTr'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: RegionData,
|
||||||
|
as: 'region',
|
||||||
|
attributes: ['name'],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
attributes: ['id', 'regionId'],
|
||||||
|
order: [['branchTypeId', 'ASC']],
|
||||||
|
});
|
||||||
|
const enrichedBranches = branches.map(branch => ({
|
||||||
|
...branch.toJSON(),
|
||||||
|
isMainBranch: falukantUser.mainBranchRegionId === branch.regionId,
|
||||||
|
}));
|
||||||
|
return enrichedBranches;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error in getBranches:', error);
|
||||||
|
throw new Error('Failed to retrieve branches');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new FalukantService();
|
export default new FalukantService();
|
||||||
|
|||||||
341
backend/utils/falukant/initializeFalukantPredefines.js
Normal file
@@ -0,0 +1,341 @@
|
|||||||
|
import FalukantPredefineFirstname from "../../models/falukant/predefine/firstname.js";
|
||||||
|
import FalukantPredefineLastname from "../../models/falukant/predefine/lastname.js";
|
||||||
|
import BranchType from "../../models/falukant/type/branch.js";
|
||||||
|
import ProductType from "../../models/falukant/type/product.js";
|
||||||
|
import FalukantStockType from "../../models/falukant/type/stock.js";
|
||||||
|
import TitleOfNobility from "../../models/falukant/type/title_of_nobility.js";
|
||||||
|
import TitleRequirement from "../../models/falukant/type/title_requirement.js";
|
||||||
|
|
||||||
|
export const initializeFalukantPredefines = async () => {
|
||||||
|
await initializeFalukantFirstnames();
|
||||||
|
await initializeFalukantLastnames();
|
||||||
|
await initializeFalukantStockTypes();
|
||||||
|
await initializeFalukantProducts();
|
||||||
|
await initializeFalukantTitles();
|
||||||
|
await initializeFalukantTitleRequirements();
|
||||||
|
await initializeFalukantBranchTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
const initializeFalukantFirstnames = async () => {
|
||||||
|
await FalukantPredefineFirstname.bulkCreate([
|
||||||
|
{ name: "Alexander", gender: "male" },
|
||||||
|
{ name: "Ben", gender: "male" },
|
||||||
|
{ name: "Christian", gender: "male" },
|
||||||
|
{ name: "Daniel", gender: "male" },
|
||||||
|
{ name: "Elias", gender: "male" },
|
||||||
|
{ name: "Felix", gender: "male" },
|
||||||
|
{ name: "Gabriel", gender: "male" },
|
||||||
|
{ name: "Hans", gender: "male" },
|
||||||
|
{ name: "Ismail", gender: "male" },
|
||||||
|
{ name: "Jakob", gender: "male" },
|
||||||
|
{ name: "Kai", gender: "male" },
|
||||||
|
{ name: "Lukas", gender: "male" },
|
||||||
|
{ name: "Maximilian", gender: "male" },
|
||||||
|
{ name: "Niklas", gender: "male" },
|
||||||
|
{ name: "Oliver", gender: "male" },
|
||||||
|
{ name: "Paul", gender: "male" },
|
||||||
|
{ name: "Quentin", gender: "male" },
|
||||||
|
{ name: "Robert", gender: "male" },
|
||||||
|
{ name: "Sebastian", gender: "male" },
|
||||||
|
{ name: "Thomas", gender: "male" },
|
||||||
|
{ name: "Ulf", gender: "male" },
|
||||||
|
{ name: "Vincent", gender: "male" },
|
||||||
|
{ name: "Thorsten", gender: "male" },
|
||||||
|
{ name: "Ulrich", gender: "male" },
|
||||||
|
{ name: "Torben", gender: "male" },
|
||||||
|
{ name: "Torsten", gender: "male" },
|
||||||
|
{ name: "Uwe", gender: "male" },
|
||||||
|
{ name: "Viktor", gender: "male" },
|
||||||
|
{ name: "Wolfgang", gender: "male" },
|
||||||
|
{ name: "Xaver", gender: "male" },
|
||||||
|
{ name: "Yannik", gender: "male" },
|
||||||
|
{ name: "Zacharias", gender: "male" },
|
||||||
|
{ name: "Aaron", gender: "male" },
|
||||||
|
{ name: "Bruno", gender: "male" },
|
||||||
|
{ name: "Carl", gender: "male" },
|
||||||
|
{ name: "David", gender: "male" },
|
||||||
|
{ name: "Emil", gender: "male" },
|
||||||
|
{ name: "Fabian", gender: "male" },
|
||||||
|
{ name: "Georg", gender: "male" },
|
||||||
|
{ name: "Heinrich", gender: "male" },
|
||||||
|
{ name: "Ian", gender: "male" },
|
||||||
|
{ name: "Jonas", gender: "male" },
|
||||||
|
{ name: "Karl", gender: "male" },
|
||||||
|
{ name: "Leon", gender: "male" },
|
||||||
|
{ name: "Matthias", gender: "male" },
|
||||||
|
{ name: "Nils", gender: "male" },
|
||||||
|
{ name: "Oskar", gender: "male" },
|
||||||
|
{ name: "Peter", gender: "male" },
|
||||||
|
{ name: "Ralf", gender: "male" },
|
||||||
|
{ name: "Simon", gender: "male" },
|
||||||
|
{ name: "Tobias", gender: "male" },
|
||||||
|
{ name: "Ulrich", gender: "male" },
|
||||||
|
{ name: "Vince", gender: "male" },
|
||||||
|
{ name: "Walter", gender: "male" },
|
||||||
|
{ name: "Xeno", gender: "male" },
|
||||||
|
{ name: "Yves", gender: "male" },
|
||||||
|
{ name: "Zeno", gender: "male" },
|
||||||
|
{ name: "Anna", gender: "female" },
|
||||||
|
{ name: "Berit", gender: "female" },
|
||||||
|
{ name: "Charlotte", gender: "female" },
|
||||||
|
{ name: "Diana", gender: "female" },
|
||||||
|
{ name: "Emilia", gender: "female" },
|
||||||
|
{ name: "Fiona", gender: "female" },
|
||||||
|
{ name: "Greta", gender: "female" },
|
||||||
|
{ name: "Hanna", gender: "female" },
|
||||||
|
{ name: "Isabelle", gender: "female" },
|
||||||
|
{ name: "Johanna", gender: "female" },
|
||||||
|
{ name: "Katharina", gender: "female" },
|
||||||
|
{ name: "Lena", gender: "female" },
|
||||||
|
{ name: "Marie", gender: "female" },
|
||||||
|
{ name: "Nina", gender: "female" },
|
||||||
|
{ name: "Olivia", gender: "female" },
|
||||||
|
{ name: "Paula", gender: "female" },
|
||||||
|
{ name: "Quirina", gender: "female" },
|
||||||
|
{ name: "Rebecca", gender: "female" },
|
||||||
|
{ name: "Sophia", gender: "female" },
|
||||||
|
{ name: "Theresa", gender: "female" },
|
||||||
|
{ name: "Ulrike", gender: "female" },
|
||||||
|
{ name: "Valeria", gender: "female" },
|
||||||
|
{ name: "Wilma", gender: "female" },
|
||||||
|
{ name: "Xenia", gender: "female" },
|
||||||
|
{ name: "Yara", gender: "female" },
|
||||||
|
{ name: "Zoe", gender: "female" },
|
||||||
|
{ name: "Antonia", gender: "female" },
|
||||||
|
{ name: "Beate", gender: "female" },
|
||||||
|
{ name: "Carla", gender: "female" },
|
||||||
|
{ name: "Dorothea", gender: "female" },
|
||||||
|
{ name: "Elisabeth", gender: "female" },
|
||||||
|
{ name: "Franziska", gender: "female" },
|
||||||
|
{ name: "Gerda", gender: "female" },
|
||||||
|
{ name: "Helena", gender: "female" },
|
||||||
|
{ name: "Irene", gender: "female" },
|
||||||
|
{ name: "Julia", gender: "female" },
|
||||||
|
{ name: "Klara", gender: "female" },
|
||||||
|
{ name: "Leonie", gender: "female" },
|
||||||
|
{ name: "Marlene", gender: "female" },
|
||||||
|
{ name: "Nele", gender: "female" },
|
||||||
|
{ name: "Petra", gender: "female" },
|
||||||
|
{ name: "Renate", gender: "female" },
|
||||||
|
{ name: "Sandra", gender: "female" },
|
||||||
|
{ name: "Tanja", gender: "female" },
|
||||||
|
{ name: "Ursula", gender: "female" },
|
||||||
|
{ name: "Vanessa", gender: "female" },
|
||||||
|
{ name: "Waltraud", gender: "female" },
|
||||||
|
{ name: "Xaveria", gender: "female" },
|
||||||
|
{ name: "Yvonne", gender: "female" },
|
||||||
|
{ name: "Zora", gender: "female" },
|
||||||
|
], {
|
||||||
|
ignoreDuplicates: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const initializeFalukantLastnames = async () => {
|
||||||
|
await FalukantPredefineLastname.bulkCreate([
|
||||||
|
{ name: "Adler" },
|
||||||
|
{ name: "Bauer" },
|
||||||
|
{ name: "Becker" },
|
||||||
|
{ name: "Bergmann" },
|
||||||
|
{ name: "Braun" },
|
||||||
|
{ name: "Busch" },
|
||||||
|
{ name: "Dreyer" },
|
||||||
|
{ name: "Eberhardt" },
|
||||||
|
{ name: "Fischer" },
|
||||||
|
{ name: "Franke" },
|
||||||
|
{ name: "Friedrich" },
|
||||||
|
{ name: "Geiger" },
|
||||||
|
{ name: "Gärtner" },
|
||||||
|
{ name: "Hartmann" },
|
||||||
|
{ name: "Hoffmann" },
|
||||||
|
{ name: "Hofmann" },
|
||||||
|
{ name: "Horn" },
|
||||||
|
{ name: "Huber" },
|
||||||
|
{ name: "Jäger" },
|
||||||
|
{ name: "Jung" },
|
||||||
|
{ name: "Kaiser" },
|
||||||
|
{ name: "Keller" },
|
||||||
|
{ name: "Klein" },
|
||||||
|
{ name: "Koch" },
|
||||||
|
{ name: "König" },
|
||||||
|
{ name: "Krüger" },
|
||||||
|
{ name: "Lang" },
|
||||||
|
{ name: "Lehmann" },
|
||||||
|
{ name: "Ludwig" },
|
||||||
|
{ name: "Maier" },
|
||||||
|
{ name: "Meyer" },
|
||||||
|
{ name: "Müller" },
|
||||||
|
{ name: "Neumann" },
|
||||||
|
{ name: "Neff" },
|
||||||
|
{ name: "Obermeier" },
|
||||||
|
{ name: "Otto" },
|
||||||
|
{ name: "Peters" },
|
||||||
|
{ name: "Ritter" },
|
||||||
|
{ name: "Richter" },
|
||||||
|
{ name: "Rosen" },
|
||||||
|
{ name: "Schäfer" },
|
||||||
|
{ name: "Schmidt" },
|
||||||
|
{ name: "Schneider" },
|
||||||
|
{ name: "Schulz" },
|
||||||
|
{ name: "Schulze" },
|
||||||
|
{ name: "Schwarz" },
|
||||||
|
{ name: "Schuster" },
|
||||||
|
{ name: "Sommer" },
|
||||||
|
{ name: "Stein" },
|
||||||
|
{ name: "Tanner" },
|
||||||
|
{ name: "Thiel" },
|
||||||
|
{ name: "Ullmann" },
|
||||||
|
{ name: "Ullrich" },
|
||||||
|
{ name: "Vogel" },
|
||||||
|
{ name: "Voigt" },
|
||||||
|
{ name: "Wagner" },
|
||||||
|
{ name: "Walter" },
|
||||||
|
{ name: "Weber" },
|
||||||
|
{ name: "Weiß" },
|
||||||
|
{ name: "Winter" },
|
||||||
|
{ name: "Wolf" },
|
||||||
|
{ name: "Xaver" },
|
||||||
|
{ name: "Xavier" },
|
||||||
|
{ name: "Zimmer" },
|
||||||
|
{ name: "Zimmermann" },
|
||||||
|
{ name: "Albrecht" },
|
||||||
|
{ name: "Arnold" },
|
||||||
|
{ name: "Baumann" },
|
||||||
|
{ name: "Dietrich" },
|
||||||
|
{ name: "Engel" },
|
||||||
|
{ name: "Graf" },
|
||||||
|
{ name: "Kirsch" },
|
||||||
|
{ name: "Lenz" },
|
||||||
|
{ name: "Schirmer" },
|
||||||
|
{ name: "Vogt" },
|
||||||
|
{ name: "Ziegler" },
|
||||||
|
], {
|
||||||
|
ignoreDuplicates: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function initializeFalukantStockTypes() {
|
||||||
|
await FalukantStockType.bulkCreate([
|
||||||
|
{ labelTr: 'wood', cost: 15 },
|
||||||
|
{ labelTr: 'stone', cost: 25 },
|
||||||
|
{ labelTr: 'iron', cost: 100 },
|
||||||
|
{ labelTr: 'field', cost: 5 },
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function initializeFalukantProducts() {
|
||||||
|
await ProductType.bulkCreate([
|
||||||
|
{ labelTr: 'wheat', category: 1, productionTime: 2, sellCost: 7 },
|
||||||
|
{ labelTr: 'grain', category: 1, productionTime: 2, sellCost: 7 },
|
||||||
|
{ labelTr: 'carrot', category: 1, productionTime: 1, sellCost: 4 },
|
||||||
|
{ labelTr: 'fish', category: 1, productionTime: 2, sellCost: 7 },
|
||||||
|
{ labelTr: 'meat', category: 1, productionTime: 2, sellCost: 7 },
|
||||||
|
{ labelTr: 'leather', category: 1, productionTime: 2, sellCost: 7 },
|
||||||
|
{ labelTr: 'wood', category: 1, productionTime: 2, sellCost: 7 },
|
||||||
|
{ labelTr: 'stone', category: 1, productionTime: 2, sellCost: 7 },
|
||||||
|
{ labelTr: 'milk', category: 1, productionTime: 1, sellCost: 4 },
|
||||||
|
{ labelTr: 'cheese', category: 1, productionTime: 1, sellCost: 4 },
|
||||||
|
{ labelTr: 'bread', category: 1, productionTime: 1, sellCost: 4 },
|
||||||
|
{ labelTr: 'beer', category: 1, productionTime: 1, sellCost: 4 },
|
||||||
|
{ labelTr: 'iron', category: 2, productionTime: 4, sellCost: 15 },
|
||||||
|
{ labelTr: 'copper', category: 2, productionTime: 4, sellCost: 15 },
|
||||||
|
{ labelTr: 'spices', category: 2, productionTime: 8, sellCost: 30 },
|
||||||
|
{ labelTr: 'salt', category: 2, productionTime: 4, sellCost: 15 },
|
||||||
|
{ labelTr: 'sugar', category: 2, productionTime: 4, sellCost: 15 },
|
||||||
|
{ labelTr: 'vinegar', category: 2, productionTime: 4, sellCost: 15 },
|
||||||
|
{ labelTr: 'cotton', category: 2, productionTime: 4, sellCost: 15 },
|
||||||
|
{ labelTr: 'wine', category: 2, productionTime: 4, sellCost: 15 },
|
||||||
|
{ labelTr: 'gold', category: 3, productionTime: 4, sellCost: 30 },
|
||||||
|
{ labelTr: 'diamond', category: 3, productionTime: 4, sellCost: 30 },
|
||||||
|
{ labelTr: 'furniture', category: 3, productionTime: 4, sellCost: 30 },
|
||||||
|
{ labelTr: 'clothing', category: 3, productionTime: 4, sellCost: 30 },
|
||||||
|
{ labelTr: 'jewelry', category: 4, productionTime: 5, sellCost: 60 },
|
||||||
|
{ labelTr: 'painting', category: 4, productionTime: 5, sellCost: 60 },
|
||||||
|
{ labelTr: 'book', category: 4, productionTime: 5, sellCost: 60 },
|
||||||
|
{ labelTr: 'weapon', category: 4, productionTime: 5, sellCost: 60 },
|
||||||
|
{ labelTr: 'armor', category: 4, productionTime: 5, sellCost: 60 },
|
||||||
|
{ labelTr: 'shield', category: 4, productionTime: 5, sellCost: 60 },
|
||||||
|
{ labelTr: 'horse', category: 5, productionTime: 5, sellCost: 60 },
|
||||||
|
{ labelTr: 'ox', category: 5, productionTime: 5, sellCost: 60 },
|
||||||
|
], {
|
||||||
|
ignoreDuplicates: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function initializeFalukantTitles() {
|
||||||
|
await TitleOfNobility.bulkCreate([
|
||||||
|
{ labelTr: "noncivil" },
|
||||||
|
{ labelTr: "civil" },
|
||||||
|
{ labelTr: "sir" },
|
||||||
|
{ labelTr: "townlord" },
|
||||||
|
{ labelTr: "by" },
|
||||||
|
{ labelTr: "landlord" },
|
||||||
|
{ labelTr: "knight" },
|
||||||
|
{ labelTr: "baron" },
|
||||||
|
{ labelTr: "count" },
|
||||||
|
{ labelTr: "palsgrave" },
|
||||||
|
{ labelTr: "margrave" },
|
||||||
|
{ labelTr: "landgrave" },
|
||||||
|
{ labelTr: "ruler" },
|
||||||
|
{ labelTr: "elector" },
|
||||||
|
{ labelTr: "imperial-prince" },
|
||||||
|
{ labelTr: "duke" },
|
||||||
|
{ labelTr: "grand-duke" },
|
||||||
|
{ labelTr: "prince-regent" },
|
||||||
|
{ labelTr: "king" },
|
||||||
|
], {
|
||||||
|
updateOnDuplicate: ['labelTr'],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function initializeFalukantTitleRequirements() {
|
||||||
|
const titleRequirements = [
|
||||||
|
{ labelTr: "civil", requirements: [{ type: "money", value: 500 }] },
|
||||||
|
{ labelTr: "sir", requirements: [{ type: "branches", value: 2 }] },
|
||||||
|
{ labelTr: "townlord", requirements: [] },
|
||||||
|
{ labelTr: "by", requirements: [] },
|
||||||
|
{ labelTr: "landlord", requirements: [] },
|
||||||
|
{ labelTr: "knight", requirements: [] },
|
||||||
|
{ labelTr: "baron", requirements: [{ type: "branches", value: 4 }] },
|
||||||
|
{ labelTr: "count", requirements: [] },
|
||||||
|
{ labelTr: "palsgrave", requirements: [] },
|
||||||
|
{ labelTr: "margrave", requirements: [] },
|
||||||
|
{ labelTr: "landgrave", requirements: [] },
|
||||||
|
{ labelTr: "ruler", requirements: [] },
|
||||||
|
{ labelTr: "elector", requirements: [] },
|
||||||
|
{ labelTr: "imperial-prince", requirements: [] },
|
||||||
|
{ labelTr: "duke", requirements: [] },
|
||||||
|
{ labelTr: "grand-duke", requirements: [] },
|
||||||
|
{ labelTr: "prince-regent", requirements: [] },
|
||||||
|
{ labelTr: "king", requirements: [] },
|
||||||
|
];
|
||||||
|
const titles = await TitleOfNobility.findAll();
|
||||||
|
const requirementsToInsert = [];
|
||||||
|
for (let i = 0; i < titleRequirements.length; i++) {
|
||||||
|
const titleRequirement = titleRequirements[i];
|
||||||
|
const title = titles.find(t => t.labelTr === titleRequirement.labelTr);
|
||||||
|
if (!title) continue;
|
||||||
|
if (i > 1) {
|
||||||
|
const moneyRequirement = {
|
||||||
|
type: "money",
|
||||||
|
value: 5000 * Math.pow(3, i - 1),
|
||||||
|
};
|
||||||
|
titleRequirement.requirements.push(moneyRequirement);
|
||||||
|
}
|
||||||
|
for (const requirement of titleRequirement.requirements) {
|
||||||
|
requirementsToInsert.push({
|
||||||
|
titleId: title.id,
|
||||||
|
requirementType: requirement.type,
|
||||||
|
requirementValue: requirement.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await TitleRequirement.bulkCreate(requirementsToInsert, { ignoreDuplicates: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
async function initializeFalukantBranchTypes() {
|
||||||
|
await BranchType.bulkCreate([
|
||||||
|
{ labelTr: 'production', baseCost: 3000 },
|
||||||
|
{ labelTr: 'store', baseCost: 2000 },
|
||||||
|
{ labelTr: 'fullstack', baseCost: 4500},
|
||||||
|
], { ignoreDuplicates: true });
|
||||||
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
import { initializeFalukantTypes, initializeFalukantRegions } from './falukant/initializeFalukantTypes.js';
|
import { initializeFalukantTypes, initializeFalukantRegions } from './falukant/initializeFalukantTypes.js';
|
||||||
|
import { initializeFalukantPredefines } from './falukant/initializeFalukantPredefines.js';
|
||||||
|
|
||||||
const initializeFalukant = async () => {
|
const initializeFalukant = async () => {
|
||||||
await initializeFalukantTypes();
|
await initializeFalukantTypes();
|
||||||
await initializeFalukantRegions();
|
await initializeFalukantRegions();
|
||||||
|
await initializeFalukantPredefines();
|
||||||
}
|
}
|
||||||
|
|
||||||
export default initializeFalukant;
|
export default initializeFalukant;
|
||||||
@@ -19,6 +19,7 @@ const createSchemas = async () => {
|
|||||||
await sequelize.query('CREATE SCHEMA IF NOT EXISTS forum');
|
await sequelize.query('CREATE SCHEMA IF NOT EXISTS forum');
|
||||||
await sequelize.query('CREATE SCHEMA IF NOT EXISTS falukant_data');
|
await sequelize.query('CREATE SCHEMA IF NOT EXISTS falukant_data');
|
||||||
await sequelize.query('CREATE SCHEMA IF NOT EXISTS falukant_type');
|
await sequelize.query('CREATE SCHEMA IF NOT EXISTS falukant_type');
|
||||||
|
await sequelize.query('CREATE SCHEMA IF NOT EXISTS falukant_predefine');
|
||||||
};
|
};
|
||||||
|
|
||||||
const initializeDatabase = async () => {
|
const initializeDatabase = async () => {
|
||||||
|
|||||||
BIN
frontend/public/images/falukant/avatar/female.png
Normal file
|
After Width: | Height: | Size: 2.8 MiB |
BIN
frontend/public/images/falukant/avatar/male.png
Normal file
|
After Width: | Height: | Size: 2.8 MiB |
BIN
frontend/public/images/icons/falukant/bank.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
frontend/public/images/icons/falukant/branches.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
frontend/public/images/icons/falukant/darknet.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
frontend/public/images/icons/falukant/director.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
frontend/public/images/icons/falukant/events.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
frontend/public/images/icons/falukant/family.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
frontend/public/images/icons/falukant/house.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
frontend/public/images/icons/falukant/moneyhistory.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
frontend/public/images/icons/falukant/overview.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
frontend/public/images/icons/falukant/politics.png
Normal file
|
After Width: | Height: | Size: 741 B |
BIN
frontend/public/images/icons/falukant/reputation.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
frontend/public/images/icons/falukant/schooling.png
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
BIN
frontend/public/images/icons/falukant/title.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
frontend/public/images/icons/falukant/workshop.png
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
@@ -70,6 +70,9 @@ export default {
|
|||||||
newValue.on('friendloginchanged', () => {
|
newValue.on('friendloginchanged', () => {
|
||||||
this.fetchFriends();
|
this.fetchFriends();
|
||||||
});
|
});
|
||||||
|
newValue.on('reloadmenu', () => {
|
||||||
|
this.loadMenu();
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -84,12 +87,10 @@ export default {
|
|||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.$store.getters.socket) {
|
if (this.$store.getters.socket) {
|
||||||
console.log('connect sockets in navigation')
|
|
||||||
this.$store.getters.socket.on('forumschanged', (data) => {
|
this.$store.getters.socket.on('forumschanged', (data) => {
|
||||||
this.fetchForums();
|
this.fetchForums();
|
||||||
});
|
});
|
||||||
this.$store.getters.socket.on('friendloginchanged', () => {
|
this.$store.getters.socket.on('friendloginchanged', () => {
|
||||||
console.log('update friends');
|
|
||||||
this.fetchFriends();
|
this.fetchFriends();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
94
frontend/src/components/falukant/StatusBar.vue
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
<template>
|
||||||
|
<div class="statusbar">
|
||||||
|
<template v-for="item in statusItems" :key="item.key">
|
||||||
|
<div class="status-item" v-if="item.value !== null" :title="$t(`falukant.statusbar.${item.key}`)">
|
||||||
|
<span class="status-icon">{{ item.icon }}: {{ item.value }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapState } from "vuex";
|
||||||
|
import apiClient from "@/utils/axios.js";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "StatusBar",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
statusItems: [
|
||||||
|
{ key: "age", icon: "👶", value: 0 },
|
||||||
|
{ key: "wealth", icon: "💰", value: 0 },
|
||||||
|
{ key: "health", icon: "❤️", value: "Good" },
|
||||||
|
{ key: "events", icon: "📰", value: null },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(["socket"]),
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
await this.fetchStatus();
|
||||||
|
if (this.socket) {
|
||||||
|
this.socket.on("falukantUpdateStatus", this.fetchStatus);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeUnmount() {
|
||||||
|
if (this.socket) {
|
||||||
|
this.socket.off("falukantUpdateStatus", this.fetchStatus);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async fetchStatus() {
|
||||||
|
try {
|
||||||
|
const response = await apiClient.get("/api/falukant/info");
|
||||||
|
const { money, character, events } = response.data;
|
||||||
|
const { age, health } = character;
|
||||||
|
let healthStatus = '';
|
||||||
|
if (health > 90) {
|
||||||
|
healthStatus = this.$t("falukant.health.amazing");
|
||||||
|
} else if (health > 75) {
|
||||||
|
healthStatus = this.$t("falukant.health.good");
|
||||||
|
} else if (health > 50) {
|
||||||
|
healthStatus = this.$t("falukant.health.normal");
|
||||||
|
} else if (health > 25) {
|
||||||
|
healthStatus = this.$t("falukant.health.bad");
|
||||||
|
} else {
|
||||||
|
healthStatus = this.$t("falukant.health.very_bad");
|
||||||
|
}
|
||||||
|
this.statusItems = [
|
||||||
|
{ key: "age", icon: "👶", value: age },
|
||||||
|
{ key: "wealth", icon: "💰", value: money },
|
||||||
|
{ key: "health", icon: "❤️", value: healthStatus },
|
||||||
|
{ key: "events", icon: "📰", value: events || null },
|
||||||
|
];
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching status:", error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.statusbar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
width: calc(100% + 40px);
|
||||||
|
gap: 2em;
|
||||||
|
margin: -21px -20px 1.5em -20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-item {
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-icon {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
133
frontend/src/components/form/FormattedDropdown.vue
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
<template>
|
||||||
|
<div class="dropdown-container">
|
||||||
|
<div class="dropdown-header" @click="toggleDropdown">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td v-for="(column, index) in columns" :key="column.field">
|
||||||
|
{{ selected ? selected[column.field] : index === 0 ? placeholder : '' }}
|
||||||
|
</td>
|
||||||
|
<td>{{ isOpen ? '▲' : '▼' }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div v-if="isOpen" class="dropdown-list">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th v-for="column in columns" :key="column.field">{{ column.label }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="option in options" :key="option.id" @click="selectOption(option)"
|
||||||
|
:class="{ selected: option.id === selected?.id }">
|
||||||
|
<td v-for="column in columns" :key="column.field">{{ option[column.field] }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "FormattedDropdown",
|
||||||
|
props: {
|
||||||
|
options: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
columns: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: "Select an option",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
emits: ['update:modelValue'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isOpen: false,
|
||||||
|
selected: this.modelValue,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
modelValue(newVal) {
|
||||||
|
this.selected = newVal;
|
||||||
|
console.log("FormattedDropdown modelValue changed:", newVal);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggleDropdown() {
|
||||||
|
this.isOpen = !this.isOpen;
|
||||||
|
},
|
||||||
|
selectOption(option) {
|
||||||
|
this.selected = option;
|
||||||
|
this.$emit("update:modelValue", option);
|
||||||
|
this.isOpen = false;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.dropdown-container {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-header {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 2px 3px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-list {
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
left: 0;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
z-index: 50;
|
||||||
|
width: auto;
|
||||||
|
min-width: 100%;
|
||||||
|
max-width: 90vw;
|
||||||
|
max-height: 300px;
|
||||||
|
overflow-y: auto;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding: 2px 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
th,
|
||||||
|
td {
|
||||||
|
text-align: left;
|
||||||
|
padding: 4px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.selected {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:hover {
|
||||||
|
background-color: #e0e0e0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -13,6 +13,7 @@ import enSettings from './locales/en/settings.json';
|
|||||||
import enAdmin from './locales/en/admin.json';
|
import enAdmin from './locales/en/admin.json';
|
||||||
import enSocialNetwork from './locales/en/socialnetwork.json';
|
import enSocialNetwork from './locales/en/socialnetwork.json';
|
||||||
import enFriends from './locales/en/friends.json';
|
import enFriends from './locales/en/friends.json';
|
||||||
|
import enFalukant from './locales/en/falukant.json';
|
||||||
|
|
||||||
import deGeneral from './locales/de/general.json';
|
import deGeneral from './locales/de/general.json';
|
||||||
import deHeader from './locales/de/header.json';
|
import deHeader from './locales/de/header.json';
|
||||||
@@ -26,6 +27,7 @@ import deSettings from './locales/de/settings.json';
|
|||||||
import deAdmin from './locales/de/admin.json';
|
import deAdmin from './locales/de/admin.json';
|
||||||
import deSocialNetwork from './locales/de/socialnetwork.json';
|
import deSocialNetwork from './locales/de/socialnetwork.json';
|
||||||
import deFriends from './locales/de/friends.json';
|
import deFriends from './locales/de/friends.json';
|
||||||
|
import deFalukant from './locales/de/falukant.json';
|
||||||
|
|
||||||
const messages = {
|
const messages = {
|
||||||
en: {
|
en: {
|
||||||
@@ -41,6 +43,7 @@ const messages = {
|
|||||||
...enAdmin,
|
...enAdmin,
|
||||||
...enSocialNetwork,
|
...enSocialNetwork,
|
||||||
...enFriends,
|
...enFriends,
|
||||||
|
...enFalukant,
|
||||||
},
|
},
|
||||||
de: {
|
de: {
|
||||||
'Ok': 'Ok',
|
'Ok': 'Ok',
|
||||||
@@ -56,6 +59,7 @@ const messages = {
|
|||||||
...deAdmin,
|
...deAdmin,
|
||||||
...deSocialNetwork,
|
...deSocialNetwork,
|
||||||
...deFriends,
|
...deFriends,
|
||||||
|
...deFalukant,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,130 @@
|
|||||||
{
|
{
|
||||||
"falukant": {
|
"falukant": {
|
||||||
|
"statusbar": {
|
||||||
|
"age": "Alter",
|
||||||
|
"wealth": "Vermögen",
|
||||||
|
"health": "Gesundheit",
|
||||||
|
"events": "Ereignisse"
|
||||||
|
},
|
||||||
|
"health": {
|
||||||
|
"amazing": "Super",
|
||||||
|
"good": "Gut",
|
||||||
|
"normal": "Normal",
|
||||||
|
"bad": "Schlecht",
|
||||||
|
"very_bad": "Sehr schlecht"
|
||||||
|
},
|
||||||
|
"create": {
|
||||||
|
"title": "Am Spiel teilnehmen",
|
||||||
|
"gender": "Geschlecht",
|
||||||
|
"male": "Mann",
|
||||||
|
"female": "Frau",
|
||||||
|
"firstname": "Vorname",
|
||||||
|
"lastname": "Nachname",
|
||||||
|
"random": "Zufällig",
|
||||||
|
"submit": "Teilnehmen"
|
||||||
|
},
|
||||||
|
"overview": {
|
||||||
|
"title": "Falukant - Übersicht",
|
||||||
|
"metadata": {
|
||||||
|
"title": "Persönliches",
|
||||||
|
"name": "Name",
|
||||||
|
"money": "Vermögen",
|
||||||
|
"age": "Alter",
|
||||||
|
"mainbranch": "Heimatstadt"
|
||||||
|
},
|
||||||
|
"productions": {
|
||||||
|
"title": "Produktionen"
|
||||||
|
},
|
||||||
|
"stock": {
|
||||||
|
"title": "Lager"
|
||||||
|
},
|
||||||
|
"branches": {
|
||||||
|
"title": "Filialen",
|
||||||
|
"level": {
|
||||||
|
"production": "Produktion",
|
||||||
|
"store": "Verkauf",
|
||||||
|
"fullstack": "Produktion mit Verkauf"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"titles": {
|
||||||
|
"male": {
|
||||||
|
"noncivil": "Leibeigener",
|
||||||
|
"civil": "Bürgerlich",
|
||||||
|
"sir": "Herr",
|
||||||
|
"townlord": "Stadtherr",
|
||||||
|
"by": "von",
|
||||||
|
"landlord": "Landherr",
|
||||||
|
"knight": "Ritter",
|
||||||
|
"baron": "Baron",
|
||||||
|
"count": "Graf",
|
||||||
|
"palsgrave": "Pfalzgraf",
|
||||||
|
"margrave": "Markgraf",
|
||||||
|
"landgrave": "Landgraf",
|
||||||
|
"ruler": "Fürst",
|
||||||
|
"elector": "Kurfürst",
|
||||||
|
"imperial-prince": "Reichsfürst",
|
||||||
|
"duke": "Herzog",
|
||||||
|
"grand-duke": "Großherzog",
|
||||||
|
"prince-regent": "Prinzregent",
|
||||||
|
"king": "König"
|
||||||
|
},
|
||||||
|
"female": {
|
||||||
|
"noncivil": "Leibeigene",
|
||||||
|
"civil": "Bürgerlich",
|
||||||
|
"sir": "Frau",
|
||||||
|
"townlord": "Stadtherrin",
|
||||||
|
"by": "zu",
|
||||||
|
"landlord": "Landherrin",
|
||||||
|
"knight": "Freifrau",
|
||||||
|
"baron": "Baronin",
|
||||||
|
"count": "Gräfin",
|
||||||
|
"palsgrave": "Pfalzgräfin",
|
||||||
|
"margrave": "Markgräfin",
|
||||||
|
"landgrave": "Landgräfin",
|
||||||
|
"ruler": "Fürstin",
|
||||||
|
"elector": "Kurfürstin",
|
||||||
|
"imperial-prince": "Reichsfürstin",
|
||||||
|
"duke": "Herzogin",
|
||||||
|
"grand-duke": "Großherzogin",
|
||||||
|
"prince-regent": "Prinzregentin",
|
||||||
|
"king": "Königin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"branch": {
|
||||||
|
"title": "Filiale",
|
||||||
|
"selection": {
|
||||||
|
"title": "Niederlassungsauswahl",
|
||||||
|
"selected": "Ausgewählte Niederlassung",
|
||||||
|
"placeholder": "Noch keine Niederlassung ausgewählt"
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"create": "Neue Niederlassung erstellen",
|
||||||
|
"upgrade": "Aktuelle Niederlassung aufwerten",
|
||||||
|
"createAlert": "Neue Niederlassung wird erstellt.",
|
||||||
|
"upgradeAlert": "Die Niederlassung mit der ID {branchId} wird aufgewertet."
|
||||||
|
},
|
||||||
|
"director": {
|
||||||
|
"title": "Direktor-Infos",
|
||||||
|
"info": "Informationen über den Direktor der Niederlassung."
|
||||||
|
},
|
||||||
|
"sale": {
|
||||||
|
"title": "Verkauf",
|
||||||
|
"info": "Hier können Produkte verkauft werden."
|
||||||
|
},
|
||||||
|
"production": {
|
||||||
|
"title": "Produktion",
|
||||||
|
"info": "Details zur Produktion in der Niederlassung."
|
||||||
|
},
|
||||||
|
"columns": {
|
||||||
|
"city": "Stadt",
|
||||||
|
"type": "Typ"
|
||||||
|
},
|
||||||
|
"types": {
|
||||||
|
"production": "Produktion",
|
||||||
|
"store": "Verkauf",
|
||||||
|
"fullstack": "Produktion mit Verkauf"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,7 +55,12 @@
|
|||||||
"house": "Haus",
|
"house": "Haus",
|
||||||
"darknet": "Untergrund",
|
"darknet": "Untergrund",
|
||||||
"reputation": "Reputation",
|
"reputation": "Reputation",
|
||||||
"moneyhistory": "Geldfluss"
|
"moneyhistory": "Geldfluss",
|
||||||
|
"nobility": "Sozialstatus",
|
||||||
|
"politics": "Politik",
|
||||||
|
"education": "Bildung",
|
||||||
|
"health": "Gesundheit",
|
||||||
|
"bank": "Bank"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
26
frontend/src/router/adminRoutes.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import AdminInterestsView from '../views/admin/InterestsView.vue';
|
||||||
|
import AdminContactsView from '../views/admin/ContactsView.vue';
|
||||||
|
import ForumAdminView from '../dialogues/admin/ForumAdminView.vue';
|
||||||
|
|
||||||
|
const adminRoutes = [
|
||||||
|
{
|
||||||
|
path: '/admin/interests',
|
||||||
|
name: 'AdminInterests',
|
||||||
|
component: AdminInterestsView,
|
||||||
|
meta: { requiresAuth: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/admin/contacts',
|
||||||
|
name: 'AdminContacts',
|
||||||
|
component: AdminContactsView,
|
||||||
|
meta: { requiresAuth: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/admin/forum',
|
||||||
|
name: 'AdminForums',
|
||||||
|
component: ForumAdminView,
|
||||||
|
meta: { requiresAuth: true }
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default adminRoutes;
|
||||||
11
frontend/src/router/authRoutes.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import ActivateView from '../views/auth/ActivateView.vue';
|
||||||
|
|
||||||
|
const authRoutes = [
|
||||||
|
{
|
||||||
|
path: '/activate',
|
||||||
|
name: 'Activate page',
|
||||||
|
component: ActivateView
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default authRoutes;
|
||||||
26
frontend/src/router/falukantRoutes.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import BranchView from '../views/falukant/BranchView.vue';
|
||||||
|
import Createview from '../views/falukant/CreateView.vue';
|
||||||
|
import FalukantOverviewView from '../views/falukant/OverviewView.vue';
|
||||||
|
|
||||||
|
const falukantRoutes = [
|
||||||
|
{
|
||||||
|
path: '/falukant/create',
|
||||||
|
name: 'FalukantCreate',
|
||||||
|
component: Createview,
|
||||||
|
meta: { requiresAuth: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/falukant/home',
|
||||||
|
name: 'FalukantOverview',
|
||||||
|
component: FalukantOverviewView,
|
||||||
|
meta: { requiresAuth: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/falukant/branch/:branchId?',
|
||||||
|
name: 'BranchView',
|
||||||
|
component: BranchView,
|
||||||
|
meta: { requiresAuth: true },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default falukantRoutes;
|
||||||
@@ -1,23 +1,11 @@
|
|||||||
import { createRouter, createWebHistory } from 'vue-router';
|
import { createRouter, createWebHistory } from 'vue-router';
|
||||||
import store from '../store';
|
import store from '../store';
|
||||||
import HomeView from '../views/HomeView.vue';
|
import HomeView from '../views/HomeView.vue';
|
||||||
import ActivateView from '../views/auth/ActivateView.vue';
|
import authRoutes from './authRoutes';
|
||||||
import PeronalSettingsView from '../views/settings/PersonalView.vue';
|
import socialRoutes from './socialRoutes';
|
||||||
import ViewSettingsView from '../views/settings/ViewView.vue';
|
import settingsRoutes from './settingsRoutes';
|
||||||
import FlirtSettingsView from '../views/settings/FlirtView.vue';
|
import adminRoutes from './adminRoutes';
|
||||||
import SexualitySettingsView from '../views/settings/SexualityView.vue';
|
import falukantRoutes from './falukantRoutes';
|
||||||
import AccountSettingsView from '../views/settings/AccountView.vue';
|
|
||||||
import InterestsView from '../views/settings/InterestsView.vue';
|
|
||||||
import AdminInterestsView from '../views/admin/InterestsView.vue';
|
|
||||||
import AdminContactsView from '../views/admin/ContactsView.vue';
|
|
||||||
import SearchView from '../views/social/SearchView.vue';
|
|
||||||
import GalleryView from '../views/social/GalleryView.vue';
|
|
||||||
import GuestbookView from '../views/social/GuestbookView.vue';
|
|
||||||
import DiaryView from '../views/social/DiaryView.vue';
|
|
||||||
import ForumAdminView from '../dialogues/admin/ForumAdminView.vue';
|
|
||||||
import ForumView from '../views/social/ForumView.vue';
|
|
||||||
import ForumTopicView from '../views/social/ForumTopicView.vue';
|
|
||||||
import FriendsView from '../views/social/FriendsView.vue';
|
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{
|
{
|
||||||
@@ -25,110 +13,13 @@ const routes = [
|
|||||||
name: 'Home',
|
name: 'Home',
|
||||||
component: HomeView
|
component: HomeView
|
||||||
},
|
},
|
||||||
{
|
...authRoutes,
|
||||||
path: '/activate',
|
...socialRoutes,
|
||||||
name: 'Activate page',
|
...settingsRoutes,
|
||||||
component: ActivateView
|
...adminRoutes,
|
||||||
},
|
...falukantRoutes,
|
||||||
{
|
|
||||||
path: '/friends',
|
|
||||||
name: 'Friends',
|
|
||||||
component: FriendsView,
|
|
||||||
meta: { requiresAuth: true }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/socialnetwork/guestbook',
|
|
||||||
name: 'Guestbook',
|
|
||||||
component: GuestbookView,
|
|
||||||
meta: { requiresAuth: true }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/socialnetwork/search',
|
|
||||||
name: 'Search users',
|
|
||||||
component: SearchView,
|
|
||||||
meta: { requiresAuth: true }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/socialnetwork/gallery',
|
|
||||||
name: 'Gallery',
|
|
||||||
component: GalleryView,
|
|
||||||
meta: { requiresAuth: true }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/socialnetwork/forum/:id',
|
|
||||||
name: 'Forum',
|
|
||||||
component: ForumView,
|
|
||||||
meta: { requiresAuth: true }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/socialnetwork/forumtopic/:id',
|
|
||||||
name: 'ForumTopic',
|
|
||||||
component: ForumTopicView,
|
|
||||||
meta: { requiresAuth: true }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/socialnetwork/diary',
|
|
||||||
name: 'Diary',
|
|
||||||
component: DiaryView,
|
|
||||||
meta: { requiresAuth: true }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/settings/personal',
|
|
||||||
name: 'Personal settings',
|
|
||||||
component: PeronalSettingsView,
|
|
||||||
meta: { requiresAuth: true }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/settings/view',
|
|
||||||
name: 'View settings',
|
|
||||||
component: ViewSettingsView,
|
|
||||||
meta: { requiresAuth: true }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/settings/sexuality',
|
|
||||||
name: 'Sexuality settings',
|
|
||||||
component: SexualitySettingsView,
|
|
||||||
meta: { requiresAuth: true }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/settings/flirt',
|
|
||||||
name: 'Flirt settings',
|
|
||||||
component: FlirtSettingsView,
|
|
||||||
meta: { requiresAuth: true }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/settings/account',
|
|
||||||
name: 'Account settings',
|
|
||||||
component: AccountSettingsView,
|
|
||||||
meta: { requiresAuth: true }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/settings/interests',
|
|
||||||
name: 'Interests',
|
|
||||||
component: InterestsView,
|
|
||||||
meta: { requiresAuth: true }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/admin/interests',
|
|
||||||
name: 'AdminInterests',
|
|
||||||
component: AdminInterestsView,
|
|
||||||
meta: { requiresAuth: true }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/admin/contacts',
|
|
||||||
name: 'AdminContacts',
|
|
||||||
component: AdminContactsView,
|
|
||||||
meta: { requiresAuth: true }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/admin/forum',
|
|
||||||
name: 'AdminForums',
|
|
||||||
component: ForumAdminView,
|
|
||||||
meta: { requiresAuth: true }
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(import.meta.env.BASE_URL),
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
routes
|
routes
|
||||||
@@ -149,4 +40,3 @@ router.beforeEach((to, from, next) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|
||||||
|
|||||||
47
frontend/src/router/settingsRoutes.js
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import PeronalSettingsView from '../views/settings/PersonalView.vue';
|
||||||
|
import ViewSettingsView from '../views/settings/ViewView.vue';
|
||||||
|
import FlirtSettingsView from '../views/settings/FlirtView.vue';
|
||||||
|
import SexualitySettingsView from '../views/settings/SexualityView.vue';
|
||||||
|
import AccountSettingsView from '../views/settings/AccountView.vue';
|
||||||
|
import InterestsView from '../views/settings/InterestsView.vue';
|
||||||
|
|
||||||
|
const settingsRoutes = [
|
||||||
|
{
|
||||||
|
path: '/settings/personal',
|
||||||
|
name: 'Personal settings',
|
||||||
|
component: PeronalSettingsView,
|
||||||
|
meta: { requiresAuth: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/settings/view',
|
||||||
|
name: 'View settings',
|
||||||
|
component: ViewSettingsView,
|
||||||
|
meta: { requiresAuth: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/settings/sexuality',
|
||||||
|
name: 'Sexuality settings',
|
||||||
|
component: SexualitySettingsView,
|
||||||
|
meta: { requiresAuth: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/settings/flirt',
|
||||||
|
name: 'Flirt settings',
|
||||||
|
component: FlirtSettingsView,
|
||||||
|
meta: { requiresAuth: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/settings/account',
|
||||||
|
name: 'Account settings',
|
||||||
|
component: AccountSettingsView,
|
||||||
|
meta: { requiresAuth: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/settings/interests',
|
||||||
|
name: 'Interests',
|
||||||
|
component: InterestsView,
|
||||||
|
meta: { requiresAuth: true }
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default settingsRoutes;
|
||||||
54
frontend/src/router/socialRoutes.js
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import FriendsView from '../views/social/FriendsView.vue';
|
||||||
|
import SearchView from '../views/social/SearchView.vue';
|
||||||
|
import GalleryView from '../views/social/GalleryView.vue';
|
||||||
|
import GuestbookView from '../views/social/GuestbookView.vue';
|
||||||
|
import DiaryView from '../views/social/DiaryView.vue';
|
||||||
|
import ForumView from '../views/social/ForumView.vue';
|
||||||
|
import ForumTopicView from '../views/social/ForumTopicView.vue';
|
||||||
|
|
||||||
|
const socialRoutes = [
|
||||||
|
{
|
||||||
|
path: '/friends',
|
||||||
|
name: 'Friends',
|
||||||
|
component: FriendsView,
|
||||||
|
meta: { requiresAuth: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/socialnetwork/guestbook',
|
||||||
|
name: 'Guestbook',
|
||||||
|
component: GuestbookView,
|
||||||
|
meta: { requiresAuth: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/socialnetwork/search',
|
||||||
|
name: 'Search users',
|
||||||
|
component: SearchView,
|
||||||
|
meta: { requiresAuth: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/socialnetwork/gallery',
|
||||||
|
name: 'Gallery',
|
||||||
|
component: GalleryView,
|
||||||
|
meta: { requiresAuth: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/socialnetwork/forum/:id',
|
||||||
|
name: 'Forum',
|
||||||
|
component: ForumView,
|
||||||
|
meta: { requiresAuth: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/socialnetwork/forumtopic/:id',
|
||||||
|
name: 'ForumTopic',
|
||||||
|
component: ForumTopicView,
|
||||||
|
meta: { requiresAuth: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/socialnetwork/diary',
|
||||||
|
name: 'Diary',
|
||||||
|
component: DiaryView,
|
||||||
|
meta: { requiresAuth: true }
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default socialRoutes;
|
||||||
@@ -7,10 +7,10 @@ import { io } from 'socket.io-client';
|
|||||||
|
|
||||||
const store = createStore({
|
const store = createStore({
|
||||||
state: {
|
state: {
|
||||||
isLoggedIn: false,
|
isLoggedIn: localStorage.getItem('isLoggedIn') === 'true',
|
||||||
user: null,
|
user: JSON.parse(localStorage.getItem('user')) || null,
|
||||||
language: navigator.language.startsWith('de') ? 'de' : 'en',
|
language: navigator.language.startsWith('de') ? 'de' : 'en',
|
||||||
menu: [],
|
menu: JSON.parse(localStorage.getItem('menu')) || [],
|
||||||
socket: null,
|
socket: null,
|
||||||
menuNeedsUpdate: false,
|
menuNeedsUpdate: false,
|
||||||
},
|
},
|
||||||
@@ -32,19 +32,22 @@ const store = createStore({
|
|||||||
localStorage.removeItem('user');
|
localStorage.removeItem('user');
|
||||||
localStorage.removeItem('menu');
|
localStorage.removeItem('menu');
|
||||||
state.menuNeedsUpdate = false;
|
state.menuNeedsUpdate = false;
|
||||||
// await apiClient.get('/api/auth/logout');
|
|
||||||
},
|
},
|
||||||
setLanguage(state, language) {
|
setLanguage(state, language) {
|
||||||
state.language = language;
|
state.language = language;
|
||||||
},
|
},
|
||||||
setMenu(state, menu) {
|
setMenu(state, menu) {
|
||||||
state.menu = menu;
|
state.menu = menu;
|
||||||
|
localStorage.setItem('menu', JSON.stringify(menu));
|
||||||
state.menuNeedsUpdate = false;
|
state.menuNeedsUpdate = false;
|
||||||
},
|
},
|
||||||
setSocket(state, socket) {
|
setSocket(state, socket) {
|
||||||
state.socket = socket;
|
state.socket = socket;
|
||||||
},
|
},
|
||||||
clearSocket(state) {
|
clearSocket(state) {
|
||||||
|
if (state.socket) {
|
||||||
|
state.socket.disconnect();
|
||||||
|
}
|
||||||
state.socket = null;
|
state.socket = null;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -58,17 +61,20 @@ const store = createStore({
|
|||||||
}
|
}
|
||||||
await dispatch('loadMenu');
|
await dispatch('loadMenu');
|
||||||
},
|
},
|
||||||
logout({ commit, state }) {
|
logout({ commit }) {
|
||||||
if (state.socket) {
|
|
||||||
state.socket.disconnect();
|
|
||||||
commit('clearSocket');
|
commit('clearSocket');
|
||||||
}
|
|
||||||
commit('dologout');
|
commit('dologout');
|
||||||
router.push('/');
|
router.push('/');
|
||||||
},
|
},
|
||||||
initializeSocket({ commit, state }) {
|
initializeSocket({ commit, state }) {
|
||||||
if (state.isLoggedIn && state.user) {
|
if (state.isLoggedIn && state.user) {
|
||||||
const socket = io(import.meta.env.VITE_API_BASE_URL);
|
const socket = io(import.meta.env.VITE_API_BASE_URL);
|
||||||
|
socket.on('connect', () => {
|
||||||
|
socket.emit('setUserId', state.user.id);
|
||||||
|
});
|
||||||
|
socket.on('disconnect', (reason) => {
|
||||||
|
console.warn('WebSocket disconnected:', reason);
|
||||||
|
});
|
||||||
commit('setSocket', socket);
|
commit('setSocket', socket);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -91,11 +97,15 @@ const store = createStore({
|
|||||||
language: state => state.language,
|
language: state => state.language,
|
||||||
menu: state => state.menu,
|
menu: state => state.menu,
|
||||||
socket: state => state.socket,
|
socket: state => state.socket,
|
||||||
menuNeedsUpdate: state => state.menuNeedsUpdate
|
menuNeedsUpdate: state => state.menuNeedsUpdate,
|
||||||
},
|
},
|
||||||
modules: {
|
modules: {
|
||||||
dialogs,
|
dialogs,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (store.state.isLoggedIn && store.state.user) {
|
||||||
|
store.dispatch('initializeSocket');
|
||||||
|
}
|
||||||
|
|
||||||
export default store;
|
export default store;
|
||||||
|
|||||||
130
frontend/src/views/falukant/BranchView.vue
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<StatusBar />
|
||||||
|
<h2>{{ $t('falukant.branch.title') }}</h2>
|
||||||
|
|
||||||
|
<!-- Branch Selection Section -->
|
||||||
|
<div class="branch-selection">
|
||||||
|
<h3>{{ $t('falukant.branch.selection.title') }}</h3>
|
||||||
|
<div>
|
||||||
|
<FormattedDropdown :options="branches" :columns="branchColumns" v-model="selectedBranch"
|
||||||
|
:placeholder="$t('falukant.branch.selection.placeholder')" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button @click="createBranch">{{ $t('falukant.branch.actions.create') }}</button>
|
||||||
|
<button @click="upgradeBranch" :disabled="!selectedBranch">
|
||||||
|
{{ $t('falukant.branch.actions.upgrade') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Director Info Section -->
|
||||||
|
<div class="director-info">
|
||||||
|
<h3>{{ $t('falukant.branch.director.title') }}</h3>
|
||||||
|
<p v-if="selectedBranch">
|
||||||
|
{{ $t('falukant.branch.director.info', { branchName: selectedBranch.cityName }) }}
|
||||||
|
</p>
|
||||||
|
<p v-else>{{ $t('falukant.branch.director.noSelection') }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Sale Section -->
|
||||||
|
<div class="sale-section">
|
||||||
|
<h3>{{ $t('falukant.branch.sale.title') }}</h3>
|
||||||
|
<p>{{ $t('falukant.branch.sale.info') }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Production Section -->
|
||||||
|
<div class="production-section">
|
||||||
|
<h3>{{ $t('falukant.branch.production.title') }}</h3>
|
||||||
|
<p>{{ $t('falukant.branch.production.info') }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import StatusBar from '@/components/falukant/StatusBar.vue';
|
||||||
|
import FormattedDropdown from '@/components/form/FormattedDropdown.vue';
|
||||||
|
import apiClient from '@/utils/axios.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "BranchView",
|
||||||
|
components: {
|
||||||
|
StatusBar,
|
||||||
|
FormattedDropdown,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
selectedBranch: null,
|
||||||
|
branches: [],
|
||||||
|
branchColumns: [
|
||||||
|
{ field: "cityName", label: this.$t('falukant.branch.columns.city') },
|
||||||
|
{ field: "type", label: this.$t('falukant.branch.columns.type') },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
await this.loadBranches();
|
||||||
|
const branchId = this.$route.params.branchId;
|
||||||
|
console.log('route params:', this.$route.params, branchId);
|
||||||
|
if (branchId) {
|
||||||
|
console.log('branch selected');
|
||||||
|
this.selectedBranch = this.branches.find(branch => branch.id === parseInt(branchId)) || null;
|
||||||
|
} else {
|
||||||
|
console.log('main branch selected');
|
||||||
|
this.selectMainBranch();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async loadBranches() {
|
||||||
|
try {
|
||||||
|
const branchesResult = await apiClient.get('/api/falukant/branches');
|
||||||
|
this.branches = branchesResult.data.map((branch) => ({
|
||||||
|
id: branch.id,
|
||||||
|
cityName: branch.region.name,
|
||||||
|
type: this.$t(`falukant.branch.types.${branch.branchType.labelTr}`),
|
||||||
|
isMainBranch: branch.isMainBranch,
|
||||||
|
}));
|
||||||
|
// Wenn keine selectedBranch gesetzt ist, versuche die Main Branch zu wählen
|
||||||
|
if (!this.selectedBranch) {
|
||||||
|
this.selectMainBranch();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading branches:', error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selectMainBranch() {
|
||||||
|
const main = this.branches.find(b => b.isMainBranch) || null;
|
||||||
|
if (main !== this.selectedBranch) {
|
||||||
|
this.selectedBranch = main;
|
||||||
|
console.log("Main branch selected:", this.selectedBranch);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
createBranch() {
|
||||||
|
alert(this.$t('falukant.branch.actions.createAlert'));
|
||||||
|
},
|
||||||
|
upgradeBranch() {
|
||||||
|
if (this.selectedBranch) {
|
||||||
|
alert(
|
||||||
|
this.$t('falukant.branch.actions.upgradeAlert', { branchId: this.selectedBranch.id })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.branch-selection,
|
||||||
|
.director-info,
|
||||||
|
.sale-section,
|
||||||
|
.production-section {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
margin: 10px 0;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
118
frontend/src/views/falukant/CreateView.vue
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<h2>{{ $t('falukant.create.title') }}</h2>
|
||||||
|
<form @submit.prevent="createFalukant">
|
||||||
|
<label>{{ $t('falukant.create.gender') }}</label>
|
||||||
|
<select v-model="falukant.gender" required @change="randomFirstName">
|
||||||
|
<option value="male">{{ $t('falukant.create.male') }}</option>
|
||||||
|
<option value="female">{{ $t('falukant.create.female') }}</option>
|
||||||
|
</select>
|
||||||
|
<div></div>
|
||||||
|
<label>{{ $t('falukant.create.firstname') }}</label>
|
||||||
|
<input type="text" v-model="falukant.firstname" required>
|
||||||
|
<button @click="randomFirstName" type="button">{{ $t('falukant.create.random') }}</button>
|
||||||
|
<label>{{ $t('falukant.create.lastname') }}</label>
|
||||||
|
<input type="text" v-model="falukant.lastname" required>
|
||||||
|
<button @click="randomLastName" type="button">{{ $t('falukant.create.random') }}</button>
|
||||||
|
<button type="submit">{{ $t('falukant.create.submit') }}</button>
|
||||||
|
</form>
|
||||||
|
<img :src="falukant.gender == 'male' ? '/images/mascot/mascot_male.png' : '/images/mascot/mascot_female.png'"
|
||||||
|
class="mascot-image" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapActions } from 'vuex';
|
||||||
|
import apiClient from '@/utils/axios.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'FalukantCreateView',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
falukant: {
|
||||||
|
gender: 'male',
|
||||||
|
firstname: '',
|
||||||
|
lastname: '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
try {
|
||||||
|
const falukantUser = await apiClient.get('/api/falukant/user');
|
||||||
|
if (falukantUser.data) {
|
||||||
|
this.$router.push({ name: 'FalukantOverview' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
}
|
||||||
|
await this.randomFirstName();
|
||||||
|
await this.randomLastName();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(['createFalukant']),
|
||||||
|
async createFalukant() {
|
||||||
|
const newUser = await apiClient.post('/api/falukant/user', this.falukant);
|
||||||
|
console.log(newUser);
|
||||||
|
this.$router.push({ name: 'FalukantOverview' });
|
||||||
|
},
|
||||||
|
async randomFirstName() {
|
||||||
|
const randomNameResult = await apiClient.get('/api/falukant/name/randomfirstname/' + this.falukant.gender);
|
||||||
|
this.falukant.firstname = randomNameResult.data.name;
|
||||||
|
console.log(this.falukant, randomNameResult);
|
||||||
|
},
|
||||||
|
async randomLastName() {
|
||||||
|
const randomNameResult = await apiClient.get('/api/falukant/name/randomlastname');
|
||||||
|
this.falukant.lastname = randomNameResult.data.name;
|
||||||
|
console.log(this.falukant, randomNameResult);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
form {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto 1fr auto;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
row-gap: 15px;
|
||||||
|
width: fit-content;
|
||||||
|
margin: 0 auto;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
text-align: right;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
select,
|
||||||
|
input {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
button[type="submit"] {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
justify-self: start;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mascot-image {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
height: calc(100vh - 400px);
|
||||||
|
max-height: 100%;
|
||||||
|
min-height: 150px;
|
||||||
|
width: auto;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
187
frontend/src/views/falukant/OverviewView.vue
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<StatusBar />
|
||||||
|
<h2>{{ $t('falukant.overview.title') }}</h2>
|
||||||
|
<div class="overviewcontainer">
|
||||||
|
<div>
|
||||||
|
<h3>{{ $t('falukant.overview.metadata.title') }}</h3>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>{{ $t('falukant.overview.metadata.name') }}</td>
|
||||||
|
<td>{{ falukantUser?.character.definedFirstName.name }} {{
|
||||||
|
falukantUser?.character.definedLastName.name }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ $t('falukant.overview.metadata.money') }}</td>
|
||||||
|
<td>{{ falukantUser?.money }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ $t('falukant.overview.metadata.age') }}</td>
|
||||||
|
<td>{{ falukantUser?.character.age }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ $t('falukant.overview.metadata.mainbranch') }}</td>
|
||||||
|
<td>{{ falukantUser?.mainBranchRegion.name }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>{{ $t('falukant.overview.productions.title') }}</h3>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>{{ $t('falukant.overview.stock.title') }}</h3>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>{{ $t('falukant.overview.branches.title') }}</h3>
|
||||||
|
<table>
|
||||||
|
<tr v-for="branch in falukantUser?.branches">
|
||||||
|
<td><span @click="openBranch(branch.id)" class="link">{{ branch.region.name }}</span></td>
|
||||||
|
<td>{{ $t(`falukant.overview.branches.level.${branch.branchType.labelTr}`) }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="imagecontainer">
|
||||||
|
<div :style="getAvatarStyle" class="avatar"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import apiClient from '@/utils/axios.js';
|
||||||
|
import StatusBar from '@/components/falukant/StatusBar.vue';
|
||||||
|
|
||||||
|
const AVATAR_POSITIONS = {
|
||||||
|
male: {
|
||||||
|
width: 195,
|
||||||
|
height: 300,
|
||||||
|
positions: {
|
||||||
|
"0-1": { x: 161, y: 28 },
|
||||||
|
"2-3": { x: 802, y: 28 },
|
||||||
|
"4-6": { x: 1014, y: 28 },
|
||||||
|
"7-10": { x: 800, y: 368 },
|
||||||
|
"11-13": { x: 373, y: 368 },
|
||||||
|
"14-16": { x: 1441, y: 28 },
|
||||||
|
"17-20": { x: 1441, y: 368 },
|
||||||
|
"21-30": { x: 1014, y: 368 },
|
||||||
|
"31-45": { x: 1227, y: 368 },
|
||||||
|
"45-55": { x: 803, y: 687 },
|
||||||
|
"55+": { x: 1441, y: 687 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
female: {
|
||||||
|
width: 223,
|
||||||
|
height: 298,
|
||||||
|
positions: {
|
||||||
|
"0-1": { x: 302, y: 66 },
|
||||||
|
"2-3": { x: 792, y: 66 },
|
||||||
|
"4-6": { x: 62, y: 66 },
|
||||||
|
"7-10": { x: 1034, y: 66 },
|
||||||
|
"11-13": { x: 1278, y: 66 },
|
||||||
|
"14-16": { x: 303, y: 392 },
|
||||||
|
"17-20": { x: 1525, y: 392 },
|
||||||
|
"21-30": { x: 1278, y: 392 },
|
||||||
|
"31-45": { x: 547, y: 718 },
|
||||||
|
"45-55": { x: 1034, y: 718 },
|
||||||
|
"55+": { x: 1525, y: 718 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'FalukantOverviewView',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
falukantUser: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
StatusBar,
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
await this.fetchFalukantUser();
|
||||||
|
if (this.socket) {
|
||||||
|
this.socket.on("falukantUserUpdated", this.fetchFalukantUser);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeUnmount() {
|
||||||
|
if (this.socket) {
|
||||||
|
this.socket.off("falukantUserUpdated", this.fetchFalukantUser);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
getAvatarStyle() {
|
||||||
|
if (!this.falukantUser) return {};
|
||||||
|
const { gender, age } = this.falukantUser.character;
|
||||||
|
const imageUrl = `/images/falukant/avatar/${gender}.png`;
|
||||||
|
const ageGroup = this.getAgeGroup(age);
|
||||||
|
const genderData = AVATAR_POSITIONS[gender] || {};
|
||||||
|
const position = genderData.positions?.[ageGroup] || { x: 0, y: 0 };
|
||||||
|
const width = genderData.width || 100;
|
||||||
|
const height = genderData.height || 100;
|
||||||
|
return {
|
||||||
|
backgroundImage: `url(${imageUrl})`,
|
||||||
|
backgroundPosition: `-${position.x}px -${position.y}px`,
|
||||||
|
backgroundSize: "1792px 1024px",
|
||||||
|
width: `${width}px`,
|
||||||
|
height: `${height}px`,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getAgeGroup(age) {
|
||||||
|
if (age <= 1) return "0-1";
|
||||||
|
if (age <= 3) return "2-3";
|
||||||
|
if (age <= 6) return "4-6";
|
||||||
|
if (age <= 10) return "7-10";
|
||||||
|
if (age <= 13) return "11-13";
|
||||||
|
if (age <= 16) return "14-16";
|
||||||
|
if (age <= 20) return "17-20";
|
||||||
|
if (age <= 30) return "21-30";
|
||||||
|
if (age <= 45) return "31-45";
|
||||||
|
if (age <= 55) return "45-55";
|
||||||
|
return "55+";
|
||||||
|
},
|
||||||
|
async fetchFalukantUser() {
|
||||||
|
const falukantUser = await apiClient.get('/api/falukant/user');
|
||||||
|
if (!falukantUser.data) {
|
||||||
|
this.$router.push({ name: 'FalukantCreate' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.falukantUser = falukantUser.data;
|
||||||
|
},
|
||||||
|
openBranch(branchId) {
|
||||||
|
this.$router.push({ name: 'BranchView', params: { branchId: branchId } });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.overviewcontainer {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||||
|
grid-gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overviewcontainer>div {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.imagecontainer {
|
||||||
|
margin-top: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
image-rendering: crisp-edges;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
14
package-lock.json
generated
@@ -9,7 +9,6 @@
|
|||||||
"version": "3.0.0-pre-alpha.0.1",
|
"version": "3.0.0-pre-alpha.0.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"mitt": "^3.0.1",
|
|
||||||
"sequelize-cli": "^6.6.2"
|
"sequelize-cli": "^6.6.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -483,11 +482,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/cross-spawn": {
|
"node_modules/cross-spawn": {
|
||||||
"version": "6.0.5",
|
"version": "6.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz",
|
||||||
"integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
|
"integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nice-try": "^1.0.4",
|
"nice-try": "^1.0.4",
|
||||||
"path-key": "^2.0.1",
|
"path-key": "^2.0.1",
|
||||||
@@ -1830,12 +1828,6 @@
|
|||||||
"node": ">=16 || 14 >=14.17"
|
"node": ">=16 || 14 >=14.17"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mitt": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/ms": {
|
"node_modules/ms": {
|
||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
|
|||||||