Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 08:24:37 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,8 @@ interface TimeshiftSpreadsheetProps {
|
||||
export function TimeshiftSpreadsheet({ teamId, teamName }: TimeshiftSpreadsheetProps) {
|
||||
const spreadsheetRef = React.useRef<HTMLDivElement>(null)
|
||||
const jspreadsheetInstance = React.useRef<unknown>(null)
|
||||
const isActiveRef = React.useRef<boolean>(true)
|
||||
const isMergingRef = React.useRef<boolean>(false)
|
||||
const currentDate = new Date()
|
||||
const [selectedMonth, setSelectedMonth] = React.useState<string>((currentDate.getMonth() + 1).toString())
|
||||
const [selectedYear, setSelectedYear] = React.useState<string>(currentDate.getFullYear().toString())
|
||||
@@ -80,14 +82,11 @@ export function TimeshiftSpreadsheet({ teamId, teamName }: TimeshiftSpreadsheetP
|
||||
|
||||
console.log("Generated", dayCount, "days of data")
|
||||
|
||||
// Complete employee data from Excel file - exact order from source xlsx
|
||||
// Complete employee data from Excel file - cleaned up without empty rows, kontrolní řádek, and X BEZ zkušeností s VN
|
||||
const employees = [
|
||||
"", // Empty row after header (row 8 in xlsx)
|
||||
"Pauzer Libor (all in one)",
|
||||
"Vörös Pavel (NN)",
|
||||
"Janouš Petr (VN)",
|
||||
"", // Empty row (row 12 in xlsx)
|
||||
"", // Empty row (row 13 in xlsx)
|
||||
"Dvořák Václav (VN)",
|
||||
"Vondrák Pavel (NN)",
|
||||
"Čeleda Olda (NN)",
|
||||
@@ -101,11 +100,7 @@ export function TimeshiftSpreadsheet({ teamId, teamName }: TimeshiftSpreadsheetP
|
||||
"Zábranský Petr (NN)",
|
||||
"Žemlička Miroslav (NN)",
|
||||
"Teslík Hynek (NN)",
|
||||
"X BEZ zkušeností s VN",
|
||||
"kontrolní řádek",
|
||||
"", // Empty row (row 29 in xlsx)
|
||||
"Pohotovost IT", // Header - will be made bold
|
||||
"", // Empty row (row 31 in xlsx)
|
||||
"Vörös Pavel",
|
||||
"Janouš Petr",
|
||||
"Glaser Ondřej",
|
||||
@@ -152,6 +147,8 @@ export function TimeshiftSpreadsheet({ teamId, teamName }: TimeshiftSpreadsheetP
|
||||
|
||||
React.useEffect(() => {
|
||||
console.log("useEffect triggered - Month:", selectedMonth, "Year:", selectedYear, "Force:", forceUpdate)
|
||||
isActiveRef.current = true
|
||||
|
||||
const loadJSpreadsheet = async () => {
|
||||
console.log("Starting loadJSpreadsheet function")
|
||||
|
||||
@@ -215,10 +212,33 @@ export function TimeshiftSpreadsheet({ teamId, teamName }: TimeshiftSpreadsheetP
|
||||
|
||||
if (spreadsheetRef.current && jexcelLib) {
|
||||
console.log("Initializing spreadsheet...")
|
||||
// Clear previous instance
|
||||
// Clear previous instance and reset any merge states
|
||||
if (jspreadsheetInstance.current) {
|
||||
console.log("Destroying previous instance")
|
||||
jspreadsheetInstance.current.destroy()
|
||||
try {
|
||||
const instance = jspreadsheetInstance.current as any
|
||||
// Clear any existing merges before destroying
|
||||
if (instance.removeMerge && instance.getMerge) {
|
||||
try {
|
||||
const merges = instance.getMerge()
|
||||
if (merges && Array.isArray(merges)) {
|
||||
merges.forEach((merge: any) => {
|
||||
try {
|
||||
instance.removeMerge(merge.address)
|
||||
} catch (e) {
|
||||
// Ignore individual merge removal errors
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
// Ignore merge clearing errors
|
||||
}
|
||||
}
|
||||
instance.destroy()
|
||||
} catch (error) {
|
||||
console.error("Error destroying instance:", error)
|
||||
}
|
||||
jspreadsheetInstance.current = null
|
||||
}
|
||||
|
||||
// Use monthly data if month/year selected, otherwise use basic data
|
||||
@@ -313,9 +333,8 @@ export function TimeshiftSpreadsheet({ teamId, teamName }: TimeshiftSpreadsheetP
|
||||
styles[`BZ${row}`] = (styles[`BZ${row}`] || "") + " border-left: 1px solid #000000;"
|
||||
}
|
||||
|
||||
// Make header rows bold
|
||||
styles["A27"] = "font-weight: bold;" // "kontrolní řádek"
|
||||
styles["A29"] = "font-weight: bold;" // "Pohotovost IT"
|
||||
// Make "Pohotovost IT" header bold (employee index 16, so row 23)
|
||||
styles["A23"] = "font-weight: bold;" // "Pohotovost IT"
|
||||
}
|
||||
|
||||
console.log("Initializing jspreadsheet with config:", {
|
||||
@@ -338,41 +357,125 @@ export function TimeshiftSpreadsheet({ teamId, teamName }: TimeshiftSpreadsheetP
|
||||
tableWidth: "100%",
|
||||
tableHeight: "500px",
|
||||
style: styles,
|
||||
onchange: (instance: any, cell: HTMLElement, x: number, y: number, value: string) => {
|
||||
// Skip onChange events during merging process to prevent infinite loops
|
||||
if (isMergingRef.current) {
|
||||
console.log("Skipping onChange during merge:", { x, y, value })
|
||||
return
|
||||
}
|
||||
|
||||
console.log("onChange triggered:", { x, y, value })
|
||||
|
||||
// Only process if component is still active
|
||||
if (!isActiveRef.current || !jspreadsheetInstance.current) return
|
||||
|
||||
// Apply rotation to first row (y === 0) when text is entered
|
||||
if (y === 0 && value && value.trim()) {
|
||||
console.log("First row change detected, applying rotation...")
|
||||
setTimeout(() => {
|
||||
if (!isActiveRef.current || !spreadsheetRef.current) return
|
||||
|
||||
try {
|
||||
const table = spreadsheetRef.current?.querySelector('.jexcel tbody')
|
||||
if (table) {
|
||||
const rows = table.querySelectorAll('tr')
|
||||
if (rows[0]) {
|
||||
const cells = rows[0].querySelectorAll('td')
|
||||
const targetCell = cells[x + 1] as HTMLElement // +1 because first cell is row number
|
||||
console.log("Target cell found:", !!targetCell, "Cell content:", targetCell?.textContent)
|
||||
if (targetCell) {
|
||||
targetCell.innerHTML = `<div style="transform: rotate(-90deg); font-size: 12px; height: 20px; display: flex; align-items: center; justify-content: center; white-space: nowrap;">${value}</div>`
|
||||
console.log("Rotation applied to cell:", targetCell)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error applying rotation:", error)
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
console.log("jspreadsheet initialized:", !!jspreadsheetInstance.current)
|
||||
|
||||
// Apply cell merges for header rows after initialization
|
||||
// DISABLED: Mutation observer for first row rotation
|
||||
// This was causing popup issues when switching tabs
|
||||
// TODO: Implement a different approach for first row rotation if needed
|
||||
|
||||
// Apply cell merges for header rows after initialization - with improved error handling
|
||||
setTimeout(() => {
|
||||
if (jspreadsheetInstance.current && selectedMonth && selectedYear) {
|
||||
if (!isActiveRef.current || !jspreadsheetInstance.current || !selectedMonth || !selectedYear) return
|
||||
|
||||
try {
|
||||
const instance = jspreadsheetInstance.current as any
|
||||
if (instance.setMerge) {
|
||||
if (!instance.setMerge) return
|
||||
|
||||
console.log("Starting cell merging process...")
|
||||
|
||||
// Set merging flag to prevent onChange events during merge process
|
||||
isMergingRef.current = true
|
||||
|
||||
// Clear any existing merges first to start fresh
|
||||
if (instance.removeMerge && instance.getMerge) {
|
||||
try {
|
||||
// Merge all pairs in rows 1, 2, 3, 4, 5 (title, day names, year, month, day)
|
||||
const totalCols = data[0]?.length || 0
|
||||
for (let row = 1; row <= 5; row++) {
|
||||
for (let col = 1; col < totalCols; col += 2) {
|
||||
const colLetter = getExcelColumnName(col)
|
||||
|
||||
// Skip merging for BZ and CA columns
|
||||
if (colLetter === 'BZ' || colLetter === 'CA') {
|
||||
continue
|
||||
}
|
||||
|
||||
const existingMerges = instance.getMerge()
|
||||
if (existingMerges && Array.isArray(existingMerges)) {
|
||||
existingMerges.forEach((merge: any) => {
|
||||
try {
|
||||
// Correct syntax: setMerge(cellAddress, colspan, rowspan)
|
||||
instance.setMerge(`${colLetter}${row}`, 2, 1) // 2 columns, 1 row
|
||||
} catch (error) {
|
||||
// Silently skip merge errors
|
||||
instance.removeMerge(merge.address)
|
||||
} catch (e) {
|
||||
// Ignore errors - merge might not exist
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error during merging:", error)
|
||||
} catch (e) {
|
||||
// Ignore errors getting existing merges
|
||||
}
|
||||
}
|
||||
|
||||
// Now apply new merges
|
||||
const totalCols = data[0]?.length || 0
|
||||
let mergeCount = 0
|
||||
|
||||
for (let row = 1; row <= 5; row++) {
|
||||
for (let col = 1; col < totalCols; col += 2) {
|
||||
// Double check we're still active
|
||||
if (!isActiveRef.current || !jspreadsheetInstance.current) {
|
||||
console.log("Component became inactive during merging")
|
||||
isMergingRef.current = false
|
||||
return
|
||||
}
|
||||
|
||||
const colLetter = getExcelColumnName(col)
|
||||
|
||||
// Skip merging for BZ and CA columns
|
||||
if (colLetter === 'BZ' || colLetter === 'CA') {
|
||||
continue
|
||||
}
|
||||
|
||||
try {
|
||||
const cellAddress = `${colLetter}${row}`
|
||||
console.log(`Attempting to merge: ${cellAddress}`)
|
||||
instance.setMerge(cellAddress, 2, 1) // 2 columns, 1 row
|
||||
mergeCount++
|
||||
} catch (error) {
|
||||
console.warn(`Failed to merge ${colLetter}${row}:`, error.message)
|
||||
// Continue with other merges even if one fails
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Successfully applied ${mergeCount} cell merges`)
|
||||
|
||||
// Clear merging flag after completion
|
||||
isMergingRef.current = false
|
||||
|
||||
} catch (error) {
|
||||
console.error("General error during cell merging:", error)
|
||||
isMergingRef.current = false
|
||||
}
|
||||
}, 100)
|
||||
}, 300) // Increased timeout to ensure spreadsheet is fully ready
|
||||
|
||||
// Apply counter-clockwise rotation to data values only (exclude second column which contains field labels)
|
||||
setTimeout(() => {
|
||||
@@ -427,8 +530,11 @@ export function TimeshiftSpreadsheet({ teamId, teamName }: TimeshiftSpreadsheetP
|
||||
})
|
||||
|
||||
return () => {
|
||||
isActiveRef.current = false
|
||||
isMergingRef.current = false
|
||||
if (jspreadsheetInstance.current) {
|
||||
jspreadsheetInstance.current.destroy()
|
||||
jspreadsheetInstance.current = null
|
||||
}
|
||||
}
|
||||
}, [teamId, selectedMonth, selectedYear, forceUpdate])
|
||||
|
||||
@@ -146,3 +146,5 @@
|
||||
2025-07-30 07:24:44 +02:00: ✅ Restore point created
|
||||
2025-07-30 07:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
|
||||
2025-07-30 07:54:37 +02:00: 🔖 Creating restore point...
|
||||
2025-07-30 07:54:43 +02:00: ✅ Restore point created
|
||||
2025-07-30 08:24:37 +02:00: 🔖 Creating restore point...
|
||||
|
||||
@@ -142,3 +142,5 @@
|
||||
2025-07-30 07:24:44 +02:00: ✅ Restore point created
|
||||
2025-07-30 07:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
|
||||
2025-07-30 07:54:37 +02:00: 🔖 Creating restore point...
|
||||
2025-07-30 07:54:43 +02:00: ✅ Restore point created
|
||||
2025-07-30 08:24:37 +02:00: 🔖 Creating restore point...
|
||||
|
||||
Reference in New Issue
Block a user