feat(ClubSettings): add country and state code fields for regional calendar data
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 43s

- Introduced `countryCode` and `stateCode` fields in the Club model to support regional calendar data.
- Updated ClubSettings component to allow users to select their country and state, enhancing the configuration options for clubs.
- Enhanced the ClubService to handle normalization of country and state codes during updates.
- Added new routes and middleware to support the training cancellation feature and calendar integration in the backend.
- Updated frontend navigation to include a calendar link, improving user access to scheduling features.
This commit is contained in:
Torsten Schulz (local)
2026-05-12 23:46:07 +02:00
parent 1e23171370
commit bea5facb7d
46 changed files with 4286 additions and 12 deletions

View File

@@ -30,6 +30,19 @@ const Club = sequelize.define('Club', {
field: 'auto_fetch_rankings',
comment: 'Enable automatic TTR/QTTR rankings fetch for this club'
},
countryCode: {
type: DataTypes.STRING(2),
allowNull: false,
defaultValue: 'DE',
field: 'country_code',
comment: 'ISO 3166-1 alpha-2 country code for regional calendar data'
},
stateCode: {
type: DataTypes.STRING(16),
allowNull: true,
field: 'state_code',
comment: 'ISO 3166-2 subdivision code for regional calendar data, e.g. DE-NW'
},
memberDataQualityRequirements: {
type: DataTypes.JSON,
allowNull: true,

View File

@@ -0,0 +1,51 @@
import { DataTypes } from 'sequelize';
import sequelize from '../database.js';
import Club from './Club.js';
const TrainingCancellation = sequelize.define('TrainingCancellation', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
},
clubId: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: Club,
key: 'id',
},
onDelete: 'CASCADE',
},
startDate: {
type: DataTypes.DATEONLY,
allowNull: false,
field: 'start_date',
},
endDate: {
type: DataTypes.DATEONLY,
allowNull: false,
field: 'end_date',
},
date: {
type: DataTypes.DATEONLY,
allowNull: true,
},
reason: {
type: DataTypes.STRING(255),
allowNull: true,
},
}, {
tableName: 'training_cancellations',
underscored: true,
timestamps: true,
indexes: [
{
unique: true,
fields: ['club_id', 'start_date', 'end_date'],
},
],
});
export default TrainingCancellation;

View File

@@ -58,6 +58,7 @@ import TrainingGroup from './TrainingGroup.js';
import MemberTrainingGroup from './MemberTrainingGroup.js';
import ClubDisabledPresetGroup from './ClubDisabledPresetGroup.js';
import TrainingTime from './TrainingTime.js';
import TrainingCancellation from './TrainingCancellation.js';
import BillingTemplate from './BillingTemplate.js';
import BillingTemplateField from './BillingTemplateField.js';
import BillingRun from './BillingRun.js';
@@ -407,6 +408,8 @@ ClubDisabledPresetGroup.belongsTo(Club, { foreignKey: 'clubId', as: 'club' });
// Training Times
TrainingGroup.hasMany(TrainingTime, { foreignKey: 'trainingGroupId', as: 'trainingTimes' });
TrainingTime.belongsTo(TrainingGroup, { foreignKey: 'trainingGroupId', as: 'trainingGroup' });
Club.hasMany(TrainingCancellation, { foreignKey: 'clubId', as: 'trainingCancellations' });
TrainingCancellation.belongsTo(Club, { foreignKey: 'clubId', as: 'club' });
// Billing
Club.hasMany(BillingTemplate, { foreignKey: 'clubId', as: 'billingTemplates' });
@@ -484,6 +487,7 @@ export {
MemberTrainingGroup,
ClubDisabledPresetGroup,
TrainingTime,
TrainingCancellation,
BillingTemplate,
BillingTemplateField,
BillingRun,