AGS/widget/Agenda.tsx

100 lines
2.6 KiB
TypeScript

import { App, Astal, Gdk } from "astal/gtk3";
import { bind, execAsync, interval, timeout, Variable } from "astal";
type AgendaItem = {
startDate: string;
startHour: string;
endDate: string;
endHour: string;
activity: string;
};
function transform(stdout: string): AgendaItem {
const [startDate, startHour, endDate, endHour, activity] = stdout.split("\t");
return { startDate, startHour, endDate, endHour, activity };
}
// Helper function to get the day name from a date string
function getDayName(dateString: string): string {
const date = new Date(dateString);
const dayNames = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
];
return dayNames[date.getDay()];
}
// Helper function to format the agenda
function createAgenda(agendaItems: AgendaItem[]): string {
// Group items by date
const groupedByDate: { [date: string]: AgendaItem[] } = {};
agendaItems.forEach((item) => {
if (!groupedByDate[item.startDate]) {
groupedByDate[item.startDate] = [];
}
groupedByDate[item.startDate].push(item);
});
// Format each group with extra space between them
let result = "";
for (const date in groupedByDate) {
const dayName = getDayName(date);
result += `\n${date} - ${dayName}\n`; // Include the day name
groupedByDate[date].forEach((item) => {
result += `\t${item.startHour} - ${item.endHour} | ${item.activity}\n`;
});
result += "\n"; // Add extra space between date groups
}
return result.trim();
}
export default function Agenda(gdkmonitor: Gdk.Monitor) {
const agenda = Variable([] as AgendaItem[]);
const watch = () => {
agenda.set([]);
agenda.stopWatch();
agenda.watch(["gcalcli", "agenda", "--tsv"], (stdout, prev) => [
...prev,
transform(stdout),
]);
};
agenda.onError((err) => {
console.error(`failed to fetch agenda: ${err}`);
timeout(5000, watch);
});
const intervalHandler = interval(1000 * 60 * 10 /* 10 minutes */, watch);
return (
<window
className="Agenda"
gdkmonitor={gdkmonitor}
exclusivity={Astal.Exclusivity.EXCLUSIVE}
anchor={Astal.WindowAnchor.RIGHT | Astal.WindowAnchor.TOP}
layer={Astal.Layer.BOTTOM}
application={App}
>
<button
borderWidth={0}
onClick={() => {
execAsync(["xdg-open", "https://www.google.com/calendar"]);
}}
>
<box
onDestroy={() => {
intervalHandler.cancel();
agenda.drop();
}}
>
{bind(agenda).as(createAgenda)}
</box>
</button>
</window>
);
}