import { createPinia, defineStore } from 'pinia' import Axios from 'axios' import schema from '@/data/profileSchema.json' import Ajv from 'ajv' import WIP from '@/components/WIP.vue' import MappingConfig from '@/components/old/MappingConfig.vue' import KnobFeedbackConfig from '@/components/config/knob/KnobFeedbackConfig.vue' import KnobLightConfig from '@/components/config/knob/KnobLightConfig.vue' import KeyLightConfig from '@/components/config/keys/KeyLightConfig.vue' const ajv = new Ajv() export const useStore = defineStore('main', { state: () => { return { profileCategories: [], selectedProfileId: null, connected: false, selectedFeature: 'knob', selectedKey: 'a', currentConfigPage: 'mapping', configPages: { knob: { mapping: { titleKey: 'config_options.mapping_configuration.title', component: MappingConfig, }, feedback: { titleKey: 'config_options.feedback_designer.title', component: KnobFeedbackConfig, }, lighting: { titleKey: 'config_options.light_designer.title', component: KnobLightConfig, }, }, key: { mapping: { titleKey: 'config_options.mapping_configuration.title', component: MappingConfig, }, lighting: { titleKey: 'config_options.light_designer.title', component: KeyLightConfig, }, }, }, } }, getters: { profiles: (state) => state.profileCategories.flatMap(c => c.profiles), profileIds: (state) => state.profiles.map(p => p.id), selectedProfileCategory: (state) => state.profileCategories.find(c => c.profiles.find(p => p.id === state.selectedProfileId)), selectedProfile: (state) => state.profiles.find(p => p.id === state.selectedProfileId), currentConfigComponent: (state) => state.configPages[state.selectedFeature][state.currentConfigPage]?.component || WIP, currentConfigPages: (state) => state.configPages[state.selectedFeature] || {}, }, actions: { selectProfile(id) { if (!this.profileIds.includes(id)) return false this.selectedProfileId = id return true }, addProfile(profile, categoryIndex, newIndex) { const category = this.profileCategories[categoryIndex] category.profiles.splice(newIndex, 0, profile) }, removeProfile(profileId) { const category = this.profileCategories.find(c => c.profiles.find(p => p.id === profileId)) const index = category.profiles.findIndex(p => p.id === profileId) category.profiles.splice(index, 1) }, duplicateProfile(profileId) { const originalProfile = this.profiles.find(p => p.id === profileId) const newProfile = JSON.parse(JSON.stringify(originalProfile)) newProfile.id = this.newProfileId(originalProfile.id) newProfile.name = this.newProfileName(originalProfile.name) const category = this.categories.find(c => c.profiles.find(p => p.id === profileId)) category.profiles.push(newProfile) return newProfile.id }, moveProfile(profileId, oldIndex, newIndex) { // Find the profile category, then swap the profiles at the old and new indices const category = this.profileCategories.find(c => c.profiles.find(p => p.id === profileId)) const tmpProfile = category.profiles[newIndex] category.profiles[newIndex] = category.profiles[oldIndex] category.profiles[newIndex] = tmpProfile }, changeProfileCategory(profileId, newCategoryIndex, newIndex) { const profile = this.profiles.find(p => p.id === profileId) const oldCategory = this.profileCategories.find(c => c.profiles.find(p => p.id === profileId)) const newCategory = this.profileCategories[newCategoryIndex] oldCategory.profiles = oldCategory.profiles.filter(p => p.id !== profileId) newCategory.profiles.splice(newIndex, 0, profile) }, renameProfile(profileId, newName) { const profile = this.profiles.find(p => p.id === profileId) profile.name = newName }, fetchProfiles() { Axios.get('http://localhost:3001/categories').then((res) => { const categories = res.data console.log(categories) const ids = new Set() const validate = ajv.compile(schema) this.$patch({ profileCategories: categories.map((category) => ({ name: category.name, profiles: category.profiles.filter((profile) => { // TODO: Validation seems to be broken right now if (!validate(profile)) { console.error('Failed to validate profile: ' + profile.name, validate.errors) return false } if (ids.has(profile.id)) { console.error('Duplicate profile id: ' + profile.id + ' for profile: ' + profile.name) return false } ids.add(profile.id) return true }), })), selectedProfileId: categories[0]?.profiles[0]?.id || null, }) }).catch((err) => { console.error(err) }) }, newProfileName(originalName = '') { let name = originalName let i = 1 while (this.profiles.find(p => p.name === name)) { name = `${originalName} (${i++})` } return name }, newProfileId(originalId = '') { let id = originalId if (originalId) { do { id = Math.floor((parseInt(id) + 1) % 9999).toString().padStart(4, '0') } while (this.profileIds.includes(id)) } else { do { id = Math.floor(Math.random() * 9999).toString().padStart(4, '0') } while (this.profileIds.includes(id)) } return id }, selectConfigFeature(feature) { this.selectedFeature = feature if (!this.currentConfigPages[this.currentConfigPage]) this.setCurrentConfigPage('mapping') }, selectKey(key) { this.selectedKey = key this.selectConfigFeature('key') }, setCurrentConfigPage(page) { this.currentConfigPage = page }, setConnected(connected) { this.connected = connected }, }, }) export const pinia = createPinia()