Skip to content

Commit ebefa79

Browse files
committed
fix upload error
1 parent 74cf964 commit ebefa79

File tree

1 file changed

+66
-12
lines changed

1 file changed

+66
-12
lines changed

docs/index.html

Lines changed: 66 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ <h1>Timesheet</h1>
430430
const SPREADSHEET_ID = "1FTzC7-1Eqj7G-y7fiG6Hq8EIk24EwCC_IQIo0qFZglY";
431431
const SHEET_NAME = "Data"; // <-- set to your tab name exactly
432432
const SCOPES = "https://www.googleapis.com/auth/spreadsheets"; // read+write
433+
const SHEET_HEADER = ["month", "date", "start", "end", "duty", "lunch", "hours", "updatedAt"];
433434

434435
let accessToken = null;
435436
let tokenClient = null;
@@ -484,6 +485,21 @@ <h1>Timesheet</h1>
484485
return res.json();
485486
}
486487

488+
function hasHeaderRow(values) {
489+
const firstRow = values[0] || [];
490+
return SHEET_HEADER.every((h, i) => String(firstRow[i] || "").toLowerCase() === h);
491+
}
492+
493+
async function ensureHeaderRow(values) {
494+
if (values.length) return values;
495+
const headerRange = encodeURIComponent(`${SHEET_NAME}!A1:H1`);
496+
await sheetsFetch(`values/${headerRange}?valueInputOption=RAW`, {
497+
method: "PUT",
498+
body: JSON.stringify({ values: [SHEET_HEADER] })
499+
});
500+
return [SHEET_HEADER];
501+
}
502+
487503
// ====== YOUR APP HOOKS ======
488504
// Implement these two functions in your app:
489505
// - getMonthDataForSync(monthKey) -> array of row objects for that month
@@ -493,12 +509,47 @@ <h1>Timesheet</h1>
493509
// { month:"2026-03", date:"2026-03-01", start:"08:15", end:"14:45", duty:"Kitchen", lunch:"0.5", hours:"5.75" }
494510

495511
function getMonthDataForSync(monthKey) {
496-
// TODO: return your local month rows
497-
return [];
512+
const month = store.months[monthKey];
513+
if (!month?.rows) return [];
514+
return month.rows
515+
.filter(r => r.date)
516+
.map(r => ({
517+
month: monthKey,
518+
date: r.date || "",
519+
start: r.start || "",
520+
end: r.end || "",
521+
duty: r.duty || "",
522+
lunch: r.lunch ?? "",
523+
hours: fmt2(calcHours(r.start, r.end, r.lunch))
524+
}));
498525
}
499526

500527
function applyMonthDataFromSync(monthKey, rows) {
501-
// TODO: write rows into local storage + re-render
528+
if (!store.months[monthKey]) {
529+
store.months[monthKey] = makeBlankMonth(monthKey);
530+
if (!store.monthOrder.includes(monthKey)) store.monthOrder.push(monthKey);
531+
}
532+
533+
const month = store.months[monthKey];
534+
const rowByDate = new Map(rows.map(r => [r.date, r]));
535+
536+
month.rows = month.rows.map(localRow => {
537+
const incoming = rowByDate.get(localRow.date);
538+
if (!incoming) return localRow;
539+
return {
540+
...localRow,
541+
start: incoming.start || "",
542+
end: incoming.end || "",
543+
duty: incoming.duty || "",
544+
lunch: incoming.lunch ?? localRow.lunch ?? "0.5",
545+
day: weekdayShort(new Date(localRow.date + "T00:00:00"))
546+
};
547+
});
548+
549+
saveStore(store);
550+
renderMonthOptions(store, monthKey);
551+
currentMonth = monthKey;
552+
renderTable(store, monthKey);
502553
}
503554

504555
// ====== SYNC DOWN: load month from sheet ======
@@ -510,9 +561,7 @@ <h1>Timesheet</h1>
510561
const range = encodeURIComponent(`${SHEET_NAME}!A:H`);
511562
const data = await sheetsFetch(`values/${range}`);
512563
const values = data.values || [];
513-
514-
// Expect header in row 1
515-
const body = values.slice(1);
564+
const body = hasHeaderRow(values) ? values.slice(1) : values;
516565
const filtered = body
517566
.filter(r => (r[0] || "") === monthKey)
518567
.map(r => ({
@@ -542,20 +591,25 @@ <h1>Timesheet</h1>
542591
// 1) Read entire sheet to find existing rows for that month+date
543592
const rangeAll = encodeURIComponent(`${SHEET_NAME}!A:H`);
544593
const data = await sheetsFetch(`values/${rangeAll}`);
545-
const values = data.values || [];
546-
const header = values[0] || [];
547-
const body = values.slice(1);
594+
const values = await ensureHeaderRow(data.values || []);
595+
const headerExists = hasHeaderRow(values);
596+
const body = headerExists ? values.slice(1) : values;
548597

549598
// Map existing row -> sheet row index (1-based in Sheets; header is row 1)
550599
const indexByKey = new Map();
600+
const firstDataRowIndex = headerExists ? 2 : 1;
551601
body.forEach((r, i) => {
552602
const m = r[0] || "";
553603
const d = r[1] || "";
554-
if (m && d) indexByKey.set(`${m}|${d}`, i + 2); // +2 because header row + 1-based
604+
if (m && d) indexByKey.set(`${m}|${d}`, i + firstDataRowIndex);
555605
});
556606

557607
// 2) Upsert each local row
558608
const localRows = getMonthDataForSync(monthKey);
609+
if (!localRows.length) {
610+
setSyncStatus("No rows to save for this month");
611+
return;
612+
}
559613
const now = new Date().toISOString();
560614

561615
for (const row of localRows) {
@@ -591,11 +645,11 @@ <h1>Timesheet</h1>
591645
}
592646
}
593647

594-
setSyncStatus("Saved ✅");
648+
setSyncStatus(`Saved ✅ (${localRows.length} rows)`);
595649
} catch (e) {
596650
setSyncStatus(String(e.message || e));
597651
}
598652
});
599653
</script>
600654
</body>
601-
</html>
655+
</html>

0 commit comments

Comments
 (0)