Val Town is a social website to write and deploy JavaScript.
Build APIs and schedule functions from your browser.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/** @jsxImportSource https://esm.sh/react */
import { createClient } from "https://esm.sh/@supabase/supabase-js";
import DOMPurify from "https://esm.sh/dompurify";
import { marked } from "https://esm.sh/marked";
import React, { useEffect, useState } from "https://esm.sh/react";
import { createRoot } from "https://esm.sh/react-dom/client";
interface Metadata {
totalScraps: number;
scrapsByDay: Record<string, number>;
tagCounts: Record<string, number>;
}
function App() {
const [summary, setSummary] = useState<string>("");
const [loading, setLoading] = useState<boolean>(true);
const [debugInfo, setDebugInfo] = useState<string[]>([]);
const [metadata, setMetadata] = useState<Metadata | null>(null);
const [currentWeek, setCurrentWeek] = useState<Date>(() => {
const urlParams = new URLSearchParams(window.location.search);
const weekParam = urlParams.get("week");
return weekParam ? new Date(weekParam) : new Date();
});
useEffect(() => {
fetchScrapsAndGenerateSummary(currentWeek);
updateUrlState(currentWeek);
}, [currentWeek]);
const fetchScrapsAndGenerateSummary = async (weekStart: Date) => {
setLoading(true);
setSummary("");
setMetadata(null);
setDebugInfo([]);
try {
setDebugInfo(
prev => [...prev, `Fetching scraps and generating summary for week of ${weekStart.toDateString()}...`],
);
const response = await fetch(`/api/summary?week=${weekStart.toISOString()}`);
const data = await response.json();
if (data.error) {
throw new Error(data.error);
}
setDebugInfo(prev => [
...prev,
`Fetched ${data.scrapCount} scraps for the week of ${weekStart.toDateString()}`,
"Summary generated successfully",
]);
setSummary(data.summary);
setMetadata(data.metadata);
} catch (error) {
console.error("Error fetching summary:", error);
setDebugInfo(prev => [...prev, `Error: ${error.message}`]);
setSummary("Error generating summary. Please check the debug information and try again later.");
} finally {
setLoading(false);
}
};
const updateUrlState = (weekStart: Date) => {
const newUrl = new URL(window.location.href);
newUrl.searchParams.set("week", weekStart.toISOString().split("T")[0]);
window.history.pushState({}, "", newUrl);
};
const changeWeek = (offset: number) => {
const newWeek = new Date(currentWeek);
newWeek.setDate(newWeek.getDate() + offset * 7);
setCurrentWeek(newWeek);
};
const renderMarkdown = (content: string) => {
const rawMarkup = marked(content);
const sanitizedMarkup = DOMPurify.sanitize(rawMarkup);
return { __html: sanitizedMarkup };
};
return (
<div className="container mx-auto px-4 py-8 max-w-4xl">
<h1 className="text-4xl font-bold mb-8">EJ Fox's Weekly Work Summary</h1>
<div className="flex justify-between items-center mb-8">
<button onClick={() => changeWeek(-1)} className="px-4 py-2 border rounded">Previous Week</button>
<span className="text-xl font-semibold">Week of {currentWeek.toDateString()}</span>
<button onClick={() => changeWeek(1)} className="px-4 py-2 border rounded">Next Week</button>
</div>
<div className="mb-8 p-4 bg-gray-100 rounded">
<h3 className="text-xl font-semibold mb-2 text-xs">Debug Information:</h3>
<ul className="list-disc pl-5">
{debugInfo.map((info, index) => <li key={index}>{info}</li>)}
</ul>
</div>
{metadata && (
<div className="mb-8 p-4 bg-gray-100 rounded hidden">
<h3 className="text-xl font-semibold mb-2">Weekly Statistics:</h3>
<p>Total scraps: {metadata.totalScraps}</p>
<h4 className="text-lg font-semibold mt-4 mb-2">Scraps by Day:</h4>
<ul className="list-disc pl-5">
{Object.entries(metadata.scrapsByDay).map(([day, count]) => <li key={day}>{day}: {count}</li>)}
ejfox-weeksummary.web.val.run
August 25, 2024