Start making front end web pages to test every single API.

This commit is contained in:
Gabriel Brown 2024-10-07 02:56:17 -05:00
parent d7d3c63d7f
commit a2bb8023c9
7 changed files with 506 additions and 16 deletions

View File

@ -16,7 +16,11 @@ export const GET = async (request: NextRequest) => {
const messages = await fetchMessages(parseInt(userId), parseInt(partnerId));
return NextResponse.json(messages);
} catch (error) {
console.error(error);
return NextResponse.json({ message: "Error" }, { status: 500 });
console.error('Detailed error:', error);
if (error instanceof Error) {
return NextResponse.json({ message: `Error: ${error.message}` }, { status: 500 });
} else {
return NextResponse.json({ message: "Unknown error occurred" }, { status: 500 });
}
}
};

View File

@ -0,0 +1,87 @@
'use client';
import React, { useState } from 'react';
export default function TestCreateOrUpdateCountdown() {
const [relationshipId, setRelationshipId] = useState('');
const [title, setTitle] = useState('');
const [date, setDate] = useState('');
const [result, setResult] = useState<string | null>(null);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setResult(null);
try {
const response = await fetch('/api/countdown/createOrUpdateCountdown', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.NEXT_PUBLIC_API_KEY ?? '',
},
body: JSON.stringify({
relationshipId,
title,
date,
}),
});
const data = await response.json() as { message: string };
setResult(data.message);
} catch (error) {
console.error('Error:', error);
setResult('An error occurred');
}
};
return (
<main className="flex min-h-screen flex-col items-center justify-center
bg-gradient-to-b from-pink-500 to-orange-400 text-white cursor-pointer">
<div className="p-4">
<h1 className="text-2xl mb-4">Test Create or Update Countdown</h1>
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label htmlFor="relationshipId" className="block">Relationship ID:</label>
<input
type="text"
id="relationshipId"
value={relationshipId}
onChange={(e) => setRelationshipId(e.target.value)}
className="border p-2 w-full bg-black"
required
/>
</div>
<div>
<label htmlFor="title" className="block">Title:</label>
<input
type="text"
id="title"
value={title}
onChange={(e) => setTitle(e.target.value)}
className="border p-2 w-full bg-black"
required
/>
</div>
<div>
<label htmlFor="date" className="block">Date:</label>
<input
type="datetime-local"
id="date"
value={date}
onChange={(e) => setDate(e.target.value)}
className="border p-2 w-full bg-black"
required
/>
</div>
<button type="submit" className="bg-blue-500 text-white p-2 rounded">
Submit
</button>
</form>
{result && (
<div className="mt-4 p-2 rounded bg-black">
Result: {result}
</div>
)}
</div>
</main>
);
}

View File

@ -0,0 +1,57 @@
'use client';
import React, { useState } from 'react';
export default function TestGetCountdownByRelationship() {
const [relationshipId, setRelationshipId] = useState('');
const [result, setResult] = useState<string | null>(null);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setResult(null);
try {
const response = await fetch(`/api/countdown/getCountdownByRelationship?relationshipId=${relationshipId}`, {
method: 'GET',
headers: {
'x-api-key': process.env.NEXT_PUBLIC_API_KEY ?? '',
},
});
const data = await response.json() as { countdown: string };
setResult(JSON.stringify(data, null, 2));
} catch (error) {
console.error('Error:', error);
setResult('An error occurred');
}
};
return (
<main className="flex min-h-screen flex-col items-center justify-center
bg-gradient-to-b from-pink-500 to-orange-400 text-white cursor-pointer">
<div className="p-4">
<h1 className="text-2xl mb-4">Test Get Countdown By Relationship</h1>
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label htmlFor="relationshipId" className="block">Relationship ID:</label>
<input
type="text"
id="relationshipId"
value={relationshipId}
onChange={(e) => setRelationshipId(e.target.value)}
className="border p-2 w-full bg-black"
required
/>
</div>
<button type="submit" className="bg-blue-500 text-white p-2 rounded">
Submit
</button>
</form>
{result && (
<div className="mt-4 p-2 rounded bg-black">
<pre>{result}</pre>
</div>
)}
</div>
</main>
);
};

View File

@ -0,0 +1,69 @@
"use client";
import React, { useState } from "react";
export default function TestFetchMessages() {
const [userId, setUserId] = useState("");
const [partnerId, setPartnerId] = useState("");
const [result, setResult] = useState<string | null>(null);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setResult(null);
try {
const response = await fetch(`/api/messages/fetchMessages?userId=${userId}&partnerId=${partnerId}`, {
method: "GET",
headers: {
"x-api-key": process.env.NEXT_PUBLIC_API_KEY ?? "",
},
});
const data = await response.json() as { message: string };
setResult(JSON.stringify(data, null, 2));
} catch (error) {
console.error("Error:", error);
setResult("An error occurred");
}
};
return (
<main className="flex min-h-screen flex-col items-center justify-center
bg-gradient-to-b from-pink-500 to-orange-400 text-white cursor-pointer">
<div className="p-4">
<h1 className="text-2xl mb-4">Test Fetch Messages</h1>
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label htmlFor="userId" className="block">User ID:</label>
<input
type="text"
id="userId"
value={userId}
onChange={(e) => setUserId(e.target.value)}
className="border p-2 w-full bg-black"
required
/>
</div>
<div>
<label htmlFor="partnerId" className="block">Partner ID:</label>
<input
type="text"
id="partnerId"
value={partnerId}
onChange={(e) => setPartnerId(e.target.value)}
className="border p-2 w-full bg-black"
required
/>
</div>
<button type="submit" className="bg-blue-500 text-white p-2 rounded">
Submit
</button>
</form>
{result && (
<div className="mt-4 p-2 rounded bg-black">
<pre>{result}</pre>
</div>
)}
</div>
</main>
);
};

View File

@ -0,0 +1,121 @@
'use client';
import React, { useState } from 'react';
type MediaType = 'text' | 'image' | 'video' | 'audio' | 'file' | 'link';
export default function TestSendMessage() {
const [senderId, setSenderId] = useState('');
const [receiverId, setReceiverId] = useState('');
const [content, setContent] = useState('');
const [mediaType, setMediaType] = useState<MediaType | ''>('');
const [mediaUrl, setMediaUrl] = useState('');
const [result, setResult] = useState<string | null>(null);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setResult(null);
try {
const response = await fetch('/api/messages/sendMessage', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.NEXT_PUBLIC_API_KEY ?? '',
},
body: JSON.stringify({
senderId,
receiverId,
content,
...(mediaType && mediaUrl && { mediaType, mediaUrl }),
}),
});
const data = await response.json() as {message: string}
setResult(JSON.stringify(data, null, 2));
} catch (error) {
console.error('Error:', error);
setResult('An error occurred');
}
};
return (
<main className="flex min-h-screen flex-col items-center justify-center
bg-gradient-to-b from-pink-500 to-orange-400 text-white cursor-pointer">
<div className="p-4">
<h1 className="text-2xl mb-4">Test Send Message</h1>
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label htmlFor="senderId" className="block">Sender ID:</label>
<input
type="text"
id="senderId"
value={senderId}
onChange={(e) => setSenderId(e.target.value)}
className="border p-2 w-full bg-black"
required
/>
</div>
<div>
<label htmlFor="receiverId" className="block">Receiver ID:</label>
<input
type="text"
id="receiverId"
value={receiverId}
onChange={(e) => setReceiverId(e.target.value)}
className="border p-2 w-full bg-black"
required
/>
</div>
<div>
<label htmlFor="content" className="block">Content:</label>
<textarea
id="content"
value={content}
onChange={(e) => setContent(e.target.value)}
className="border p-2 w-full bg-black"
required
/>
</div>
<div>
<label htmlFor="mediaType" className="block">Media Type:</label>
<select
id="mediaType"
value={mediaType}
onChange={(e) => setMediaType(e.target.value as MediaType)}
className="border p-2 w-full bg-black"
>
<option value="">None</option>
<option value="image">Image</option>
<option value="video">Video</option>
<option value="audio">Audio</option>
<option value="file">File</option>
<option value="link">Link</option>
</select>
</div>
{mediaType && (
<div>
<label htmlFor="mediaUrl" className="block">Media URL:</label>
<input
type="text"
id="mediaUrl"
value={mediaUrl}
onChange={(e) => setMediaUrl(e.target.value)}
className="border p-2 w-full bg-black"
required
/>
</div>
)}
<button type="submit" className="bg-blue-500 text-white p-2 rounded">
Send Message
</button>
</form>
{result && (
<div className="mt-4 p-2 rounded bg-black">
<pre>{result}</pre>
</div>
)}
</div>
</main>
);
}

View File

@ -0,0 +1,75 @@
"use client";
import React, {useState} from "react";
export default function TestCreateRequestPage() {
const [userId, setUserId] = useState('');
const [targetUserId, setTargetUserId] = useState('');
const [result, setResult] = useState<string | null>(null)
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setResult(null);
try {
const response = await fetch('/api/relationships/createRequest', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.NEXT_PUBLIC_API_KEY ?? '',
},
body: JSON.stringify({
userId,
targetUserId,
}),
});
const data = await response.json() as {message: string};
setResult(JSON.stringify(data));
} catch (error) {
console.error('Error:', error);
setResult('An error occurred');
}
};
return (
<main className="flex min-h-screen flex-col items-center justify-center
bg-gradient-to-b from-pink-500 to-orange-400 text-white cursor-pointer">
<div className="p-4">
<h1 className="text-2xl mb-4">Create Relationship Request</h1>
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label htmlFor="userId" className="block">User ID:</label>
<input
type="text"
id="userId"
value={userId}
onChange={(e) => setUserId(e.target.value)}
className="border p-2 w-full bg-black"
required
/>
</div>
<div>
<label htmlFor="targetUserId" className="block">Target User ID:</label>
<input
type="text"
id="targetUserId"
value={targetUserId}
onChange={(e) => setTargetUserId(e.target.value)}
className="border p-2 w-full bg-black"
required
/>
</div>
<button type="submit" className="bg-blue-500 p-2 rounded">
Submit
</button>
</form>
{result && (
<div className="mt-4 p-2 rounded bg-black">
Result: {result}
</div>
)}
</div>
</main>
);
};

View File

@ -1,9 +1,10 @@
import 'server-only';
import { db } from '~/server/db';
import * as schema from '~/server/db/schema';
import { eq, and, or } from 'drizzle-orm';
import { eq, and, or, sql } from 'drizzle-orm';
import { pgEnum } from 'drizzle-orm/pg-core';
import jwt from 'jsonwebtoken';
import { inArray } from 'drizzle-orm/sql';
// --- Helper Functions --- //
@ -30,12 +31,39 @@ export const ensureUserExists = async (userId: number) => {
}
};
export const ensureRelationshipExistsByRelationshipId = async (relationshipId: number) => {
try {
const relationship = await db.select({
relationshipId: schema.userRelationships.relationshipId,
status: schema.relationships.status,
}).from(schema.userRelationships)
.leftJoin(schema.relationships,
eq(schema.userRelationships.relationshipId, schema.relationships.id))
.where(eq(schema.userRelationships.relationshipId, relationshipId));
if (relationship.length === 0) {
throw new Error("Relationship not found");
}
if (relationship[0]?.status !== 'accepted') {
throw new Error("Relationship not accepted");
}
return relationship[0];
} catch (error) {
if (error instanceof Error) {
throw new Error(`Error checking relationship: ${error.message}`);
} else {
throw new Error("Unknown error occurred while checking relationship");
}
}
};
/**
* Ensure relationship exists between a user and a partner.
* Handles both directions of a relationship (userId => partnerId or partnerId => userId).
* Optionally checks relationship status.
*/
export const ensureRelationshipExists = async (userId: number, partnerId: number, status?: 'pending' | 'accepted') => {
export const ensureRelationshipExistsOld = async (userId: number, partnerId: number, status?: 'pending' | 'accepted') => {
try {
// Ensure bidirectional relationship (user1 <-> user2 or user2 <-> user1)
const relationship = await db.select({
@ -76,6 +104,48 @@ export const ensureRelationshipExists = async (userId: number, partnerId: number
}
};
export const ensureRelationshipExists = async (userId: number, partnerId: number) => {
try {
// Ensure bidirectional relationship (user1 <-> user2 or user2 <-> user1)
const relationship = await db.select({
relationshipId: schema.userRelationships.relationshipId,
status: schema.relationships.status,
})
.from(schema.userRelationships)
.leftJoin(
schema.relationships,
eq(schema.userRelationships.relationshipId, schema.relationships.id)
)
.where(
and(
eq(schema.userRelationships.relationshipId,
db.select({ relationshipId: schema.userRelationships.relationshipId })
.from(schema.userRelationships)
.where(eq(schema.userRelationships.userId, partnerId))
.limit(1)
),
eq(schema.userRelationships.userId, userId)
)
);
if (!relationship.length) {
throw new Error('Relationship does not exist');
}
if (relationship[0]?.status !== "accepted") {
throw new Error(`Relationship is not accepted`);
}
return relationship[0];
} catch (error) {
if (error instanceof Error) {
throw new Error(`Error checking relationship: ${error.message}`);
} else {
throw new Error("Unknown error occurred while checking relationship");
}
}
};
// --- User Management Functions --- //
export const getUserById = async (userId: number) => {
@ -275,15 +345,24 @@ export const createRelationshipRequest = async (requestorId: number, requestedId
await ensureUserExists(requestedId);
// Check if a relationship exists in either direction
const existingRelationship = await db.select()
const existingRelationship = await db
.select({
relationshipId: schema.userRelationships.relationshipId,
status: schema.relationships.status,
})
.from(schema.userRelationships)
.leftJoin(schema.relationships, eq(schema.userRelationships.relationshipId, schema.relationships.id))
.where(or(
and(eq(schema.userRelationships.userId, requestorId), eq(schema.userRelationships.userId, requestedId)), // userId -> requestedId
and(eq(schema.userRelationships.userId, requestedId), eq(schema.userRelationships.userId, requestorId)) // requestedId -> userId
));
.innerJoin(
schema.relationships,
eq(schema.userRelationships.relationshipId, schema.relationships.id)
)
.where(
or(
eq(schema.userRelationships.userId, requestorId),
eq(schema.userRelationships.userId, requestedId)
)
).limit(1);
if (existingRelationship.length && existingRelationship[0]?.relationship?.status !== 'rejected') {
if (existingRelationship.length > 0) {
throw new Error('A relationship already exists or is pending between these users');
}
@ -312,7 +391,6 @@ export const createRelationshipRequest = async (requestorId: number, requestedId
}
};
export const updateRelationshipRequest = async (relationshipId: number, status: 'accepted' | 'rejected') => {
try {
const relationship = await db.select().from(schema.relationships)
@ -366,8 +444,7 @@ export const sendMessage = async (
await ensureUserExists(senderId);
await ensureUserExists(receiverId);
// Ensure the relationship exists (no need to use returned 'relationshipId' for now)
await ensureRelationshipExists(senderId, receiverId, "accepted");
await ensureRelationshipExists(senderId, receiverId);
// Insert the new message
const message = await db.insert(schema.messages).values({
@ -378,7 +455,7 @@ export const sendMessage = async (
if (!message.length || !message[0]?.id)
throw new Error("Failed to send message");
if (mediaUrl && mediaType) {
if (mediaUrl && mediaType && mediaUrl.length > 0 && mediaType !== "text") {
await db.insert(schema.messageMedia).values({
messageId: message[0].id,
mediaUrl,
@ -399,7 +476,7 @@ export const sendMessage = async (
export const fetchMessages = async (userId: number, partnerId: number) => {
try {
await ensureUserExists(userId);
await ensureRelationshipExists(userId, partnerId, "accepted");
await ensureRelationshipExists(userId, partnerId);
const messages = await db.select().from(schema.messages)
.where(or(