31setError(null);
32
33const response = await fetch(`/api/chat/rooms/${room.id}/messages`);
34const data = await response.json();
35
60
61try {
62const response = await fetch(`/api/chat/rooms/${room.id}/messages`, {
63method: 'POST',
64headers: {
1# Backend API
23This directory contains the backend API for the Side Hustle Hub application.
45## Structure
67- `index.ts`: Main entry point for the API
8- `database/`: Database schema and queries
9- `routes/`: API route handlers
1011## API Endpoints
1213### Users
1415- `POST /api/users`: Create a new user
16- `GET /api/users/:username`: Get a user by username
1718### Opportunities
1920- `GET /api/opportunities`: Get all opportunities
21- `GET /api/opportunities/category/:category`: Get opportunities by category
22- `POST /api/opportunities`: Create a new opportunity
2324### Chat
2526- `GET /api/chat/rooms`: Get all chat rooms
27- `GET /api/chat/rooms/:id`: Get a specific chat room
28- `GET /api/chat/rooms/:id/messages`: Get messages for a chat room
29- `POST /api/chat/rooms/:id/messages`: Post a message to a chat room
3031### Static Files
20app.use("*", cors());
2122// API routes
23app.route("/api/users", usersRoutes);
24app.route("/api/opportunities", opportunitiesRoutes);
25app.route("/api/chat", chatRoutes);
2627// Static routes (must be last)
7getUserById
8} from "../database/queries.ts";
9import { ApiResponse, ChatRoom, Message, MessageInput } from "../../shared/types.ts";
1011const app = new Hono();
16const rooms = await getChatRooms();
17
18return c.json<ApiResponse<ChatRoom[]>>({
19success: true,
20data: rooms
22} catch (error) {
23console.error("Error getting chat rooms:", error);
24return c.json<ApiResponse<null>>({
25success: false,
26error: "Failed to get chat rooms"
35
36if (isNaN(id)) {
37return c.json<ApiResponse<null>>({
38success: false,
39error: "Invalid room ID"
44
45if (!room) {
46return c.json<ApiResponse<null>>({
47success: false,
48error: "Chat room not found"
50}
51
52return c.json<ApiResponse<ChatRoom>>({
53success: true,
54data: room
56} catch (error) {
57console.error("Error getting chat room:", error);
58return c.json<ApiResponse<null>>({
59success: false,
60error: "Failed to get chat room"
71
72if (isNaN(roomId)) {
73return c.json<ApiResponse<null>>({
74success: false,
75error: "Invalid room ID"
80const room = await getChatRoomById(roomId);
81if (!room) {
82return c.json<ApiResponse<null>>({
83success: false,
84error: "Chat room not found"
88const messages = await getMessagesByChatRoom(roomId, limit, beforeId);
89
90return c.json<ApiResponse<Message[]>>({
91success: true,
92data: messages
94} catch (error) {
95console.error("Error getting messages:", error);
96return c.json<ApiResponse<null>>({
97success: false,
98error: "Failed to get messages"
108
109if (isNaN(roomId) || !content || !user_id) {
110return c.json<ApiResponse<null>>({
111success: false,
112error: "Room ID, content, and user_id are required"
117const room = await getChatRoomById(roomId);
118if (!room) {
119return c.json<ApiResponse<null>>({
120success: false,
121error: "Chat room not found"
126const user = await getUserById(user_id);
127if (!user) {
128return c.json<ApiResponse<null>>({
129success: false,
130error: "User not found"
140};
141
142return c.json<ApiResponse<Message>>({
143success: true,
144data: messageWithUser
146} catch (error) {
147console.error("Error posting message:", error);
148return c.json<ApiResponse<null>>({
149success: false,
150error: "Failed to post message"
6getUserById
7} from "../database/queries.ts";
8import { ApiResponse, Opportunity, OpportunityInput } from "../../shared/types.ts";
910const app = new Hono();
18const opportunities = await getOpportunities(limit, offset);
19
20return c.json<ApiResponse<Opportunity[]>>({
21success: true,
22data: opportunities
24} catch (error) {
25console.error("Error getting opportunities:", error);
26return c.json<ApiResponse<null>>({
27success: false,
28error: "Failed to get opportunities"
40const opportunities = await getOpportunitiesByCategory(category, limit, offset);
41
42return c.json<ApiResponse<Opportunity[]>>({
43success: true,
44data: opportunities
46} catch (error) {
47console.error("Error getting opportunities by category:", error);
48return c.json<ApiResponse<null>>({
49success: false,
50error: "Failed to get opportunities by category"
59
60if (!title || !description || !category || !user_id) {
61return c.json<ApiResponse<null>>({
62success: false,
63error: "Title, description, category, and user_id are required"
68const user = await getUserById(user_id);
69if (!user) {
70return c.json<ApiResponse<null>>({
71success: false,
72error: "User not found"
83);
84
85return c.json<ApiResponse<Opportunity>>({
86success: true,
87data: opportunity
89} catch (error) {
90console.error("Error creating opportunity:", error);
91return c.json<ApiResponse<null>>({
92success: false,
93error: "Failed to create opportunity"
1import { Hono } from "https://esm.sh/hono@3.11.7";
2import { createUser, getUserByUsername } from "../database/queries.ts";
3import { ApiResponse, User } from "../../shared/types.ts";
45const app = new Hono();
11
12if (!username || !display_name) {
13return c.json<ApiResponse<null>>({
14success: false,
15error: "Username and display name are required"
20const existingUser = await getUserByUsername(username);
21if (existingUser) {
22return c.json<ApiResponse<null>>({
23success: false,
24error: "Username already exists"
28const user = await createUser(username, display_name);
29
30return c.json<ApiResponse<User>>({
31success: true,
32data: user
34} catch (error) {
35console.error("Error creating user:", error);
36return c.json<ApiResponse<null>>({
37success: false,
38error: "Failed to create user"
48
49if (!user) {
50return c.json<ApiResponse<null>>({
51success: false,
52error: "User not found"
54}
55
56return c.json<ApiResponse<User>>({
57success: true,
58data: user
60} catch (error) {
61console.error("Error getting user:", error);
62return c.json<ApiResponse<null>>({
63success: false,
64error: "Failed to get user"
52}
5354// API response types
55export interface ApiResponse<T> {
56success: boolean;
57data?: T;
untitled-8939index.ts10 matches
41});
4243// API Routes
44const api = new Hono();
4546// User endpoints
47api.post("/users", async c => {
48const { name } = await c.req.json();
49
56});
5758api.get("/users/:id", async c => {
59const userId = c.req.param("id");
60const user = await getUserById(userId);
6869// Envelope endpoints
70api.post("/users/:userId/envelopes", async c => {
71const userId = c.req.param("userId");
72const { name, icon, color, budget } = await c.req.json();
80});
8182api.put("/users/:userId/envelopes/:envelopeId/allocate", async c => {
83const userId = c.req.param("userId");
84const envelopeId = c.req.param("envelopeId");
124125// Transaction endpoints
126api.post("/users/:userId/transactions/import", async c => {
127const userId = c.req.param("userId");
128const { csvContent, mapping } = await c.req.json();
148});
149150api.put("/users/:userId/transactions/:transactionId/assign", async c => {
151const userId = c.req.param("userId");
152const transactionId = c.req.param("transactionId");
164});
165166// Mount API routes
167app.route("/api", api);
168169// This is the entry point for HTTP vals
untitled-8939App.tsx7 matches
7import AchievementNotification from "./AchievementNotification.tsx";
89const API_BASE_URL = "/api";
1011const App: React.FC = () => {
46try {
47setLoading(true);
48const response = await fetch(`${API_BASE_URL}/users/${userId}`);
49
50if (!response.ok) {
66try {
67setLoading(true);
68const response = await fetch(`${API_BASE_URL}/users`, {
69method: "POST",
70headers: {
92
93try {
94const response = await fetch(`${API_BASE_URL}/users/${user.id}/envelopes`, {
95method: "POST",
96headers: {
115
116try {
117const response = await fetch(`${API_BASE_URL}/users/${user.id}/envelopes/${envelopeId}/allocate`, {
118method: "PUT",
119headers: {
139try {
140setLoading(true);
141const response = await fetch(`${API_BASE_URL}/users/${user.id}/transactions/import`, {
142method: "POST",
143headers: {
165
166try {
167const response = await fetch(`${API_BASE_URL}/users/${user.id}/transactions/${transactionId}/assign`, {
168method: "PUT",
169headers: {
untitled-8939index.html2 matches
10
11<!-- Fonts -->
12<link rel="preconnect" href="https://fonts.googleapis.com">
13<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
14<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap" rel="stylesheet">
15
16<!-- Error catching -->