19โ โ โโโ queries.ts # Database query functions
20โ โโโ routes/
21โ โ โโโ jobs.ts # Job posting API routes
22โ โ โโโ chat.ts # Chat API routes
23โ โโโ index.ts # Main Hono server
24โโโ frontend/
34```
3536## API Endpoints
3738### Jobs
39- `GET /api/jobs` - Get all job postings
40- `POST /api/jobs` - Create a new job posting
41- `DELETE /api/jobs/:id` - Delete a job posting
4243### Chat
44- `GET /api/chat/messages` - Get chat messages
45- `POST /api/chat/messages` - Send a chat message
4647## Getting Started
15await runMigrations();
1617// API routes
18app.route("/api/questions", questions);
19app.route("/api/responses", responses);
2021// Serve static files
AnonymousMyQuestions.tsx1 match
25const fetchMyQuestions = async (id: string) => {
26try {
27const response = await fetch(`/api/questions/by-anonymous-id/${id}`);
28if (!response.ok) {
29throw new Error('Failed to fetch your questions');
AnonymousResponseForm.tsx1 match
3132try {
33const res = await fetch('/api/responses', {
34method: 'POST',
35headers: {
Job-Listingchat.ts9 matches
1import { Hono } from "https://esm.sh/hono@3.11.7";
2import { getRecentMessages, createMessage } from "../database/queries.ts";
3import type { ChatMessage, ApiResponse } from "../../shared/types.ts";
45const chat = new Hono();
9try {
10const messages = await getRecentMessages(50);
11const response: ApiResponse<ChatMessage[]> = {
12success: true,
13data: messages
15return c.json(response);
16} catch (error) {
17const response: ApiResponse<ChatMessage[]> = {
18success: false,
19error: "Failed to fetch messages"
30// Basic validation
31if (!messageData.username || !messageData.message) {
32const response: ApiResponse<ChatMessage> = {
33success: false,
34error: "Username and message are required"
4243if (messageData.message.length === 0) {
44const response: ApiResponse<ChatMessage> = {
45success: false,
46error: "Message cannot be empty"
5051if (messageData.message.length > 500) {
52const response: ApiResponse<ChatMessage> = {
53success: false,
54error: "Message too long (max 500 characters)"
5859if (messageData.username.length > 50) {
60const response: ApiResponse<ChatMessage> = {
61success: false,
62error: "Username too long (max 50 characters)"
6667const newMessage = await createMessage(messageData);
68const response: ApiResponse<ChatMessage> = {
69success: true,
70data: newMessage
72return c.json(response, 201);
73} catch (error) {
74const response: ApiResponse<ChatMessage> = {
75success: false,
76error: "Failed to send message"
AnonymousQuestionFeed.tsx1 match
16const fetchQuestions = async () => {
17try {
18const response = await fetch('/api/questions');
19if (!response.ok) {
20throw new Error('Failed to fetch questions');
Job-Listingjobs.ts11 matches
1import { Hono } from "https://esm.sh/hono@3.11.7";
2import { getAllJobs, createJob, deleteJob } from "../database/queries.ts";
3import type { Job, ApiResponse } from "../../shared/types.ts";
45const jobs = new Hono();
9try {
10const jobList = await getAllJobs();
11const response: ApiResponse<Job[]> = {
12success: true,
13data: jobList
15return c.json(response);
16} catch (error) {
17const response: ApiResponse<Job[]> = {
18success: false,
19error: "Failed to fetch jobs"
31if (!jobData.title || !jobData.company || !jobData.description ||
32!jobData.location || !jobData.contact_email) {
33const response: ApiResponse<Job> = {
34success: false,
35error: "Missing required fields"
41const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
42if (!emailRegex.test(jobData.contact_email)) {
43const response: ApiResponse<Job> = {
44success: false,
45error: "Invalid email format"
4950const newJob = await createJob(jobData);
51const response: ApiResponse<Job> = {
52success: true,
53data: newJob
55return c.json(response, 201);
56} catch (error) {
57const response: ApiResponse<Job> = {
58success: false,
59error: "Failed to create job"
68const id = parseInt(c.req.param("id"));
69if (isNaN(id)) {
70const response: ApiResponse<boolean> = {
71success: false,
72error: "Invalid job ID"
77const deleted = await deleteJob(id);
78if (!deleted) {
79const response: ApiResponse<boolean> = {
80success: false,
81error: "Job not found"
84}
8586const response: ApiResponse<boolean> = {
87success: true,
88data: true
90return c.json(response);
91} catch (error) {
92const response: ApiResponse<boolean> = {
93success: false,
94error: "Failed to delete job"
untitled-288App.tsx5 matches
26setError(null);
27
28const response = await fetch("/api/quotes/daily");
29const data = await response.json();
30
44const loadCategories = async () => {
45try {
46const response = await fetch("/api/quotes/categories");
47const data = await response.json();
48setAvailableCategories(data.categories || []);
54const loadHistory = async () => {
55try {
56const response = await fetch("/api/quotes/history");
57const data: QuoteHistory = await response.json();
58setHistory(data.quotes || []);
71if (customTheme.trim()) requestBody.theme = customTheme.trim();
72
73const response = await fetch("/api/quotes/generate", {
74method: "POST",
75headers: { "Content-Type": "application/json" },
210<p className="text-gray-900 font-medium mb-2 line-clamp-2">"{quote.text}"</p>
211<div className="flex items-center justify-between text-sm text-gray-500">
212<span className="capitalize">{quote.category.replace('-', ' ')} โข {quote.theme}</span>
213<span>{new Date(quote.date).toLocaleDateString()}</span>
214</div>
AnonymousQuestionForm.tsx1 match
2829try {
30const response = await fetch('/api/questions', {
31method: 'POST',
32headers: {
Job-Listingtypes.ts1 match
19}
2021export interface ApiResponse<T> {
22success: boolean;
23data?: T;