6export async function sendEveningReminder(user: User, tasks: DailyTasks) {
7 const today = new Date().toISOString().split('T')[0];
8 const yesUrl = `${BASE_URL}/api/complete/${user.id}/${today}/true`;
9 const noUrl = `${BASE_URL}/api/complete/${user.id}/${today}/false`;
10
11 const html = `
71 const yesterdayStr = yesterday.toISOString().split('T')[0];
72
73 const yesUrl = `${BASE_URL}/api/complete/${user.id}/${yesterdayStr}/true`;
74 const noUrl = `${BASE_URL}/api/complete/${user.id}/${yesterdayStr}/false`;
75
76 const html = `
2import { readFile, serveFile } from "https://esm.town/v/std/utils@85-main/index.ts";
3import { runMigrations } from "./database/migrations.ts";
4import api from "./routes/api.ts";
5
6const app = new Hono();
14await runMigrations();
15
16// API routes
17app.route("/api", api);
18
19// Serve static files
31
32 try {
33 const response = await fetch('/api/tasks', {
34 method: 'POST',
35 headers: {
23 setLoading(true);
24 try {
25 const response = await fetch(`/api/dashboard/${encodeURIComponent(email)}`);
26 if (response.ok) {
27 const data = await response.json();
8 <script src="https://esm.town/v/std/catch"></script>
9 <style>
10 @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
11 body { font-family: 'Inter', sans-serif; }
12 </style>
1/** @jsxImportSource https://esm.sh/react@18.2.0 */
2import { useState, useEffect, useRef } from "https://esm.sh/react@18.2.0";
3import type { ChatMessage, CreateChatMessageRequest, ApiResponse } from "../../shared/types.ts";
4
5export default function ChatRoom() {
39 const fetchMessages = async () => {
40 try {
41 const response = await fetch('/api/chat/messages');
42 const result: ApiResponse<ChatMessage[]> = await response.json();
43
44 if (result.success && result.data) {
71 };
72
73 const response = await fetch('/api/chat/messages', {
74 method: 'POST',
75 headers: {
79 });
80
81 const result: ApiResponse<ChatMessage> = await response.json();
82
83 if (result.success) {
10} from "../database/queries.ts";
11
12const api = new Hono();
13
14// Submit daily tasks
15api.post("/tasks", async (c) => {
16 try {
17 const data: TaskFormData = await c.req.json();
41
42// Get dashboard data
43api.get("/dashboard/:email", async (c) => {
44 try {
45 const email = c.req.param("email");
59
60// Handle task completion response (from email)
61api.get("/complete/:userId/:date/:completed", async (c) => {
62 try {
63 const userId = parseInt(c.req.param("userId"));
116});
117
118export default api;
1/** @jsxImportSource https://esm.sh/react@18.2.0 */
2import { useState } from "https://esm.sh/react@18.2.0";
3import type { CreateJobRequest, ApiResponse, Job } from "../../shared/types.ts";
4
5interface JobFormProps {
36 };
37
38 const response = await fetch('/api/jobs', {
39 method: 'POST',
40 headers: {
44 });
45
46 const result: ApiResponse<Job> = await response.json();
47
48 if (result.success) {
26โ โ โโโ queries.ts # Database operations
27โ โโโ routes/
28โ โ โโโ api.ts # API endpoints
29โ โ โโโ email.ts # Email handling
30โ โโโ index.ts # Main server
1/** @jsxImportSource https://esm.sh/react@18.2.0 */
2import { useState, useEffect } from "https://esm.sh/react@18.2.0";
3import type { Job, ApiResponse } from "../../shared/types.ts";
4
5export default function JobBoard() {
18 try {
19 setLoading(true);
20 const response = await fetch('/api/jobs');
21 const result: ApiResponse<Job[]> = await response.json();
22
23 if (result.success && result.data) {