Save and restore session data

This commit is contained in:
2025-08-13 23:47:27 +02:00
parent 93167f162c
commit 3cb548c752
5 changed files with 224 additions and 65 deletions
+67 -18
View File
@@ -108,6 +108,8 @@ export default {
typ: '',
herkunft: '',
glaube: '',
geschlecht: '',
stand: '',
attributes: {},
derived_values: {},
skills: [],
@@ -170,14 +172,20 @@ export default {
},
async handleNext(data) {
// Merge the new data
this.sessionData = { ...this.sessionData, ...data }
// Save progress for current step before moving to next
await this.saveProgressForStep(this.currentStep, data)
// Move to next step
this.currentStep++
try {
// Merge the new data
this.sessionData = { ...this.sessionData, ...data }
// Save progress for current step before moving to next
await this.saveProgressForStep(this.currentStep, data)
// Move to next step
this.currentStep++
} catch (error) {
console.error('Failed to save progress before moving to next step:', error)
console.error('Data that failed to save:', data)
// Don't move to next step if save failed
}
},
async saveProgressForStep(step, data) {
@@ -190,12 +198,21 @@ export default {
switch (step) {
case 1:
endpoint = `/api/characters/create-session/${this.sessionId}/basic`
// Handle both old format and new basic_info format
const basicInfo = data.basic_info || data
payload = {
name: data.name || this.sessionData.name,
rasse: data.rasse || this.sessionData.rasse,
typ: data.typ || this.sessionData.typ,
herkunft: data.herkunft || this.sessionData.herkunft,
glaube: data.glaube || this.sessionData.glaube,
name: basicInfo.name || this.sessionData.name || '',
geschlecht: basicInfo.geschlecht || this.sessionData.geschlecht || '',
rasse: basicInfo.rasse || this.sessionData.rasse || '',
typ: basicInfo.typ || this.sessionData.typ || '',
herkunft: basicInfo.herkunft || this.sessionData.herkunft || '',
stand: basicInfo.stand || this.sessionData.stand || '',
glaube: basicInfo.glaube || this.sessionData.glaube || '',
}
// Validate that all required fields are present
console.log('BasicInfo payload before sending:', payload)
if (!payload.name || !payload.geschlecht || !payload.rasse || !payload.typ || !payload.herkunft || !payload.stand) {
throw new Error(`Missing required fields: name=${payload.name}, geschlecht=${payload.geschlecht}, rasse=${payload.rasse}, typ=${payload.typ}, herkunft=${payload.herkunft}, stand=${payload.stand}`)
}
break
case 2:
@@ -218,6 +235,9 @@ export default {
if (endpoint) {
console.log('Saving progress for step', step, 'with payload:', payload)
console.log('Original data received:', data)
console.log('sessionData:', this.sessionData)
console.log('basicInfo extraction:', data.basic_info || data)
const response = await API.put(endpoint, payload, {
headers: { Authorization: `Bearer ${token}` },
})
@@ -225,6 +245,20 @@ export default {
}
} catch (error) {
console.error('Error saving progress for step', step, ':', error)
if (error.response) {
console.error('Error response data:', error.response.data)
console.error('Error response status:', error.response.status)
}
// Provide more specific error messages
if (error.response && error.response.status === 401) {
alert('Your session has expired. Please log in again.')
} else if (error.response && error.response.status === 400) {
const errorMsg = error.response.data?.error || 'Invalid data submitted'
alert(`Error saving character data: ${errorMsg}`)
} else {
alert('Failed to save character data. Please try again.')
}
throw error // Re-throw to handle in calling function
}
},
@@ -237,14 +271,29 @@ export default {
// Only allow navigation to current step or previously completed steps
if (stepNumber <= this.currentStep) {
this.currentStep = stepNumber
// Save current progress before switching steps
this.saveProgress()
// Save current progress before switching steps (no data parameter needed here)
this.saveProgress().catch(error => {
console.error('Failed to save progress during navigation:', error)
})
}
},
async saveProgress() {
// Save progress for current step with current sessionData
await this.saveProgressForStep(this.currentStep, this.sessionData)
async saveProgress(data = null) {
try {
// Use provided data or current sessionData as fallback
const dataToSave = data || this.sessionData
// Update sessionData with new data if provided
if (data) {
this.sessionData = { ...this.sessionData, ...data }
}
// Save progress for current step
await this.saveProgressForStep(this.currentStep, dataToSave)
} catch (error) {
console.error('Failed to save progress:', error)
throw error
}
},
async handleFinalize() {
@@ -147,6 +147,7 @@
<script>
import API from '../../utils/api'
import { rollNotation } from '../../utils/randomUtils'
export default {
name: 'CharacterBasicInfo',
@@ -177,6 +178,7 @@ export default {
lastSocialClassRoll: null,
showOverlay: false,
overlayTimeout: null,
isInitialized: false, // Flag to prevent early watcher triggers
}
},
computed: {
@@ -193,25 +195,53 @@ export default {
'formData.typ'() {
// Clear social class roll result when character class changes
this.lastSocialClassRoll = null
},
formData: {
handler(newValue) {
// Only save if component is fully initialized
if (this.isInitialized) {
console.log('BasicInfo: formData changed, emitting save:', newValue)
console.log('BasicInfo: Field validation status:')
console.log(' name valid:', newValue.name && newValue.name.length >= 2)
console.log(' geschlecht valid:', !!newValue.geschlecht)
console.log(' rasse valid:', !!newValue.rasse)
console.log(' typ valid:', !!newValue.typ)
console.log(' herkunft valid:', !!newValue.herkunft)
console.log(' stand valid:', !!newValue.stand)
this.$emit('save', { basic_info: newValue })
}
},
deep: true
}
},
async created() {
// Initialize form with session data
console.log('BasicInfo: created() called, sessionData:', this.sessionData)
// Initialize form with session data - check both old format and new basic_info format
const basicInfo = this.sessionData.basic_info || {}
console.log('BasicInfo: extracted basicInfo:', basicInfo)
this.formData = {
name: this.sessionData.name || '',
geschlecht: this.sessionData.geschlecht || '',
rasse: this.sessionData.rasse || '',
typ: this.sessionData.typ || '',
herkunft: this.sessionData.herkunft || '',
stand: this.sessionData.stand || '',
glaube: this.sessionData.glaube || '',
name: basicInfo.name || this.sessionData.name || '',
geschlecht: basicInfo.geschlecht || this.sessionData.geschlecht || '',
rasse: basicInfo.rasse || this.sessionData.rasse || '',
typ: basicInfo.typ || this.sessionData.typ || '',
herkunft: basicInfo.herkunft || this.sessionData.herkunft || '',
stand: basicInfo.stand || this.sessionData.stand || '',
glaube: basicInfo.glaube || this.sessionData.glaube || '',
}
console.log('BasicInfo: initialized formData:', this.formData)
if (this.formData.glaube) {
this.beliefSearch = this.formData.glaube
}
// Save initial state to ensure all fields are captured
console.log('BasicInfo: Initial save, formData:', this.formData)
this.$emit('save', { basic_info: this.formData })
await this.loadReferenceData()
// Mark as initialized to enable watcher
this.isInitialized = true
},
beforeUnmount() {
// Clean up timeouts
@@ -284,7 +314,7 @@ export default {
}
// Base 1d100 roll
const baseRoll = this.$rollNotation('1d100')
const baseRoll = rollNotation('1d100')
let modifier = 0
// Apply class modifiers
@@ -332,6 +362,9 @@ export default {
result: socialClass
}
// Save the updated form data
this.$emit('save', { basic_info: this.formData })
// Show overlay notification
this.showRollOverlay()
},
@@ -359,8 +392,24 @@ export default {
},
handleSubmit() {
console.log('BasicInfo: handleSubmit called')
console.log('BasicInfo: isValid =', this.isValid)
console.log('BasicInfo: formData validation:')
console.log(' name:', this.formData.name, '(length:', this.formData.name.length, ')')
console.log(' geschlecht:', this.formData.geschlecht)
console.log(' rasse:', this.formData.rasse)
console.log(' typ:', this.formData.typ)
console.log(' herkunft:', this.formData.herkunft)
console.log(' stand:', this.formData.stand)
console.log(' glaube:', this.formData.glaube)
if (this.isValid) {
this.$emit('next', this.formData)
console.log('BasicInfo: handleSubmit, formData:', this.formData)
// Save the current state before proceeding
this.$emit('save', { basic_info: this.formData })
this.$emit('next', { basic_info: this.formData })
} else {
console.warn('BasicInfo: Form is not valid, submission blocked')
}
},
}
+17
View File
@@ -20,4 +20,21 @@ API.interceptors.request.use(
}
)
// Response interceptor to handle 401 errors
API.interceptors.response.use(
(response) => {
return response
},
(error) => {
if (error.response && error.response.status === 401) {
// Token is invalid or expired
console.warn('Authentication failed - token may be expired')
localStorage.removeItem('token')
// You might want to redirect to login here
// window.location.href = '/login'
}
return Promise.reject(error)
}
)
export default API