dont even know if I changed anything
This commit is contained in:
		
							
								
								
									
										20
									
								
								drizzle/0000_warm_edwin_jarvis.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								drizzle/0000_warm_edwin_jarvis.sql
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					CREATE OR REPLACE FUNCTION notify_new_message()
 | 
				
			||||||
 | 
					RETURNS trigger LANGUAGE plpgsql AS $$
 | 
				
			||||||
 | 
					BEGIN
 | 
				
			||||||
 | 
					  PERFORM pg_notify(
 | 
				
			||||||
 | 
					    'new_message',
 | 
				
			||||||
 | 
					    json_build_object(
 | 
				
			||||||
 | 
					      'id', NEW.id,
 | 
				
			||||||
 | 
					      'text', NEW.text,
 | 
				
			||||||
 | 
					      'senderId', NEW.senderId,
 | 
				
			||||||
 | 
					      'receiverId', NEW.receiverId,
 | 
				
			||||||
 | 
					      'createdAt', NEW.createdAt
 | 
				
			||||||
 | 
					    )::text
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					  RETURN NEW;
 | 
				
			||||||
 | 
					END;
 | 
				
			||||||
 | 
					$$;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CREATE TRIGGER message_insert_trigger
 | 
				
			||||||
 | 
					AFTER INSERT ON messages
 | 
				
			||||||
 | 
					FOR EACH ROW EXECUTE FUNCTION notify_new_message();
 | 
				
			||||||
							
								
								
									
										15
									
								
								drizzle/meta/0000_snapshot.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								drizzle/meta/0000_snapshot.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "id": "ba7dd70a-8dd6-41be-b1d2-158ab83ba830",
 | 
				
			||||||
 | 
					  "prevId": "00000000-0000-0000-0000-000000000000",
 | 
				
			||||||
 | 
					  "version": "7",
 | 
				
			||||||
 | 
					  "dialect": "postgresql",
 | 
				
			||||||
 | 
					  "tables": {},
 | 
				
			||||||
 | 
					  "enums": {},
 | 
				
			||||||
 | 
					  "schemas": {},
 | 
				
			||||||
 | 
					  "sequences": {},
 | 
				
			||||||
 | 
					  "_meta": {
 | 
				
			||||||
 | 
					    "columns": {},
 | 
				
			||||||
 | 
					    "schemas": {},
 | 
				
			||||||
 | 
					    "tables": {}
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										13
									
								
								drizzle/meta/_journal.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								drizzle/meta/_journal.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "version": "7",
 | 
				
			||||||
 | 
					  "dialect": "postgresql",
 | 
				
			||||||
 | 
					  "entries": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "idx": 0,
 | 
				
			||||||
 | 
					      "version": "7",
 | 
				
			||||||
 | 
					      "when": 1729627211020,
 | 
				
			||||||
 | 
					      "tag": "0000_warm_edwin_jarvis",
 | 
				
			||||||
 | 
					      "breakpoints": true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -12,8 +12,8 @@
 | 
				
			|||||||
    "dev": "next dev",
 | 
					    "dev": "next dev",
 | 
				
			||||||
    "lint": "next lint",
 | 
					    "lint": "next lint",
 | 
				
			||||||
    "start": "next start",
 | 
					    "start": "next start",
 | 
				
			||||||
    "go": "pnpm dev",
 | 
					    "go": "next dev",
 | 
				
			||||||
    "go:prod": "pnpm build && pnpm start"
 | 
					    "go:prod": "next build && next start"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@t3-oss/env-nextjs": "^0.10.1",
 | 
					    "@t3-oss/env-nextjs": "^0.10.1",
 | 
				
			||||||
 
 | 
				
			|||||||
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 15 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								public/favicon.png
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/favicon.png
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 16 KiB  | 
							
								
								
									
										41
									
								
								src/app/api/messages/get/route.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/app/api/messages/get/route.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					'use server';
 | 
				
			||||||
 | 
					import { NextResponse } from 'next/server';
 | 
				
			||||||
 | 
					import type { NextRequest } from 'next/server';
 | 
				
			||||||
 | 
					import { getMessages } from '~/server/functions';
 | 
				
			||||||
 | 
					import { middleware } from '~/middleware';
 | 
				
			||||||
 | 
					import type { Message } from '~/server/types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const GET = async (request: NextRequest) => {
 | 
				
			||||||
 | 
					  const middlewareResponse = await middleware(request);
 | 
				
			||||||
 | 
					  if (middlewareResponse) return middlewareResponse;
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    const url = new URL(request.url);
 | 
				
			||||||
 | 
					    const userId = Number.parseInt(url.searchParams.get('userId') ?? '');
 | 
				
			||||||
 | 
					    const limit = Number.parseInt(url.searchParams.get('limit') ?? '');
 | 
				
			||||||
 | 
					    const offset = Number.parseInt(url.searchParams.get('offset') ?? '0');
 | 
				
			||||||
 | 
					    if (!userId || isNaN(userId) || !limit || isNaN(limit) || isNaN(offset)) {
 | 
				
			||||||
 | 
					      console.log('userId: ', userId, 'limit: ', limit, 'offset: ', offset);
 | 
				
			||||||
 | 
					      return NextResponse.json(
 | 
				
			||||||
 | 
					        { message: 'Missing userId, limit, or offset' }, { status: 400 }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const messages: Message[] | undefined = await getMessages(userId, limit, offset);
 | 
				
			||||||
 | 
					    if (messages === undefined) {
 | 
				
			||||||
 | 
					      return NextResponse.json(
 | 
				
			||||||
 | 
					        { message: 'No messages found' }, { status: 404 }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return NextResponse.json(messages);
 | 
				
			||||||
 | 
					  } catch (error) {
 | 
				
			||||||
 | 
					    console.error('Error getting messages:', error);
 | 
				
			||||||
 | 
					    if (error instanceof Error) {
 | 
				
			||||||
 | 
					      return NextResponse.json(
 | 
				
			||||||
 | 
					        { message: error.message }, { status: 500 }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      return NextResponse.json(
 | 
				
			||||||
 | 
					        { message: 'Unknown error occurred' }, { status: 500 }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										41
									
								
								src/app/api/messages/send/route.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/app/api/messages/send/route.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					'use server'
 | 
				
			||||||
 | 
					import { NextResponse } from 'next/server';
 | 
				
			||||||
 | 
					import type { NextRequest } from 'next/server';
 | 
				
			||||||
 | 
					import { sendMessage } from '~/server/functions';
 | 
				
			||||||
 | 
					import { middleware } from '~/middleware';
 | 
				
			||||||
 | 
					import type { Message } from '~/server/types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const POST = async (request: NextRequest) => {
 | 
				
			||||||
 | 
					  const middlewareResponse = await middleware(request);
 | 
				
			||||||
 | 
					  if (middlewareResponse) return middlewareResponse;
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    const body = await request.json() as {
 | 
				
			||||||
 | 
					      message: Message;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const { message } = body;
 | 
				
			||||||
 | 
					    if (!message) {
 | 
				
			||||||
 | 
					      console.log('Message:', message);
 | 
				
			||||||
 | 
					      return NextResponse.json(
 | 
				
			||||||
 | 
					        { message: 'Missing message' }, { status: 400 }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const newMessage: Message | null = await sendMessage(message);
 | 
				
			||||||
 | 
					    if (!newMessage) {
 | 
				
			||||||
 | 
					      return NextResponse.json(
 | 
				
			||||||
 | 
					        { message: 'Error sending message' }, { status: 500 }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return NextResponse.json(newMessage);
 | 
				
			||||||
 | 
					  } catch (error) {
 | 
				
			||||||
 | 
					    console.error('Error sending message:', error);
 | 
				
			||||||
 | 
					    if (error instanceof Error) {
 | 
				
			||||||
 | 
					      return NextResponse.json(
 | 
				
			||||||
 | 
					        { message: error.message }, { status: 500 }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      return NextResponse.json(
 | 
				
			||||||
 | 
					        { message: 'Unknown error occurred' }, { status: 500 }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@@ -4,9 +4,9 @@ import { GeistSans } from "geist/font/sans";
 | 
				
			|||||||
import { type Metadata } from "next";
 | 
					import { type Metadata } from "next";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const metadata: Metadata = {
 | 
					export const metadata: Metadata = {
 | 
				
			||||||
  title: "Create T3 App",
 | 
					  title: "Is Madeline the Cutest?",
 | 
				
			||||||
  description: "Generated by create-t3-app",
 | 
					  description: "Answering the easiest question in the world!",
 | 
				
			||||||
  icons: [{ rel: "icon", url: "/favicon.ico" }],
 | 
					  icons: [{ rel: "icon", url: "/favicon.png" }],
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function RootLayout({
 | 
					export default function RootLayout({
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,37 +1,35 @@
 | 
				
			|||||||
import Link from "next/link";
 | 
					"use client";
 | 
				
			||||||
 | 
					import { useState, useEffect } from "react";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const interestingYes = () => {
 | 
				
			||||||
 | 
					  const yesArray = [
 | 
				
			||||||
 | 
					    "Absolutely, yes.",
 | 
				
			||||||
 | 
					    "Without a doubt.",
 | 
				
			||||||
 | 
					    "Of course.",
 | 
				
			||||||
 | 
					    "Definitely.",
 | 
				
			||||||
 | 
					    "Obviously!",
 | 
				
			||||||
 | 
					    "Certainly!",
 | 
				
			||||||
 | 
					    "Positively.",
 | 
				
			||||||
 | 
					    "100%",
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					  return yesArray[Math.floor(Math.random() * yesArray.length)];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function HomePage() {
 | 
					export default function HomePage() {
 | 
				
			||||||
 | 
					  const [currentText, setCurrentText] = useState("");
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    setCurrentText(interestingYes() ?? "Absolutely, yes.");
 | 
				
			||||||
 | 
					  }, []);
 | 
				
			||||||
 | 
					  const handleClick = () => {
 | 
				
			||||||
 | 
					    setCurrentText(interestingYes() ?? "Absolutely, yes.");
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <main className="flex min-h-screen flex-col items-center justify-center bg-gradient-to-b from-[#2e026d] to-[#15162c] text-white">
 | 
					    <main className="flex min-h-screen flex-col items-center justify-center
 | 
				
			||||||
      <div className="container flex flex-col items-center justify-center gap-12 px-4 py-16">
 | 
					      bg-gradient-to-b from-pink-500 to-orange-400 text-white cursor-pointer">
 | 
				
			||||||
        <h1 className="text-5xl font-extrabold tracking-tight text-white sm:text-[5rem]">
 | 
					      <h3 className="text-5xl font-extrabold tracking-tight
 | 
				
			||||||
          Create <span className="text-[hsl(280,100%,70%)]">T3</span> App
 | 
					        text-white sm:text-[5rem] text-center" onClick={handleClick}>
 | 
				
			||||||
        </h1>
 | 
					        {currentText}
 | 
				
			||||||
        <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 md:gap-8">
 | 
					      </h3>
 | 
				
			||||||
          <Link
 | 
					 | 
				
			||||||
            className="flex max-w-xs flex-col gap-4 rounded-xl bg-white/10 p-4 text-white hover:bg-white/20"
 | 
					 | 
				
			||||||
            href="https://create.t3.gg/en/usage/first-steps"
 | 
					 | 
				
			||||||
            target="_blank"
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            <h3 className="text-2xl font-bold">First Steps →</h3>
 | 
					 | 
				
			||||||
            <div className="text-lg">
 | 
					 | 
				
			||||||
              Just the basics - Everything you need to know to set up your
 | 
					 | 
				
			||||||
              database and authentication.
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
          </Link>
 | 
					 | 
				
			||||||
          <Link
 | 
					 | 
				
			||||||
            className="flex max-w-xs flex-col gap-4 rounded-xl bg-white/10 p-4 text-white hover:bg-white/20"
 | 
					 | 
				
			||||||
            href="https://create.t3.gg/en/introduction"
 | 
					 | 
				
			||||||
            target="_blank"
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            <h3 className="text-2xl font-bold">Documentation →</h3>
 | 
					 | 
				
			||||||
            <div className="text-lg">
 | 
					 | 
				
			||||||
              Learn more about Create T3 App, the libraries it uses, and how to
 | 
					 | 
				
			||||||
              deploy it.
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
          </Link>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </main>
 | 
					    </main>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
// https://orm.drizzle.team/docs/sql-schema-declaration
 | 
					// https://orm.drizzle.team/docs/sql-schema-declaration
 | 
				
			||||||
 | 
					import { db } from '~/server/db';
 | 
				
			||||||
import { sql } from "drizzle-orm";
 | 
					import { sql } from "drizzle-orm";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  boolean,
 | 
					  boolean,
 | 
				
			||||||
@@ -161,3 +162,4 @@ export const quickReplyOptions = pgTable(
 | 
				
			|||||||
    quickReplyIdIndex: index('qr_options_quick_reply_id_idx').on(table.quickReplyId),
 | 
					    quickReplyIdIndex: index('qr_options_quick_reply_id_idx').on(table.quickReplyId),
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
import 'server-only';
 | 
					import 'server-only';
 | 
				
			||||||
import { db } from '~/server/db';
 | 
					import { db } from '~/server/db';
 | 
				
			||||||
import * as schema from '~/server/db/schema';
 | 
					import * as schema from '~/server/db/schema';
 | 
				
			||||||
import { eq, and, or, like, not } from 'drizzle-orm';
 | 
					import { eq, and, or, like, not, desc, sql } from 'drizzle-orm';
 | 
				
			||||||
import { User,
 | 
					import { User,
 | 
				
			||||||
  Relationship,
 | 
					  Relationship,
 | 
				
			||||||
  UserRelationship,
 | 
					  UserRelationship,
 | 
				
			||||||
@@ -227,7 +227,7 @@ export const updateRelationshipStatus = async (
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
  const relationship = relationships[0] as Relationship;
 | 
					  const relationship = relationships[0] as Relationship;
 | 
				
			||||||
  // Everything above is just getting info
 | 
					  // Everything above is just getting info
 | 
				
			||||||
  if (userId === relationship.requestorId) {
 | 
					  if (userId === relationship.requestorId && status === 'accepted') {
 | 
				
			||||||
    throw new Error('The requestor cannot accept the relationship they requested.');
 | 
					    throw new Error('The requestor cannot accept the relationship they requested.');
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (status === 'accepted') {
 | 
					  if (status === 'accepted') {
 | 
				
			||||||
@@ -255,7 +255,7 @@ export const updateRelationshipStatus = async (
 | 
				
			|||||||
    return relationshipData;
 | 
					    return relationshipData;
 | 
				
			||||||
  } else if (status === 'rejected') {
 | 
					  } else if (status === 'rejected') {
 | 
				
			||||||
    await db.delete(schema.userRelationships)
 | 
					    await db.delete(schema.userRelationships)
 | 
				
			||||||
      .where(eq(schema.userRelationships.id, userRelationship.id));
 | 
					      .where(eq(schema.userRelationships.relationshipId, relationship.id));
 | 
				
			||||||
    await db.delete(schema.relationships)
 | 
					    await db.delete(schema.relationships)
 | 
				
			||||||
      .where(eq(schema.relationships.id, relationship.id));
 | 
					      .where(eq(schema.relationships.id, relationship.id));
 | 
				
			||||||
    return null;
 | 
					    return null;
 | 
				
			||||||
@@ -325,3 +325,36 @@ export const createRelationshipRequest = async (userId: number, partnerId: numbe
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getMessages = async (userId: number, limit: number, offset: number) => {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    const messages = await db.select().from(schema.messages)
 | 
				
			||||||
 | 
					      .where(or(
 | 
				
			||||||
 | 
					        eq(schema.messages.senderId, userId),
 | 
				
			||||||
 | 
					        eq(schema.messages.receiverId, userId)
 | 
				
			||||||
 | 
					      ))
 | 
				
			||||||
 | 
					      .limit(limit)
 | 
				
			||||||
 | 
					      .offset(offset)
 | 
				
			||||||
 | 
					      .orderBy(desc(schema.messages.createdAt), desc(schema.messages.id));
 | 
				
			||||||
 | 
					    return messages as Message[];
 | 
				
			||||||
 | 
					  } catch (error) {
 | 
				
			||||||
 | 
					    console.error('Error getting messages:', error);
 | 
				
			||||||
 | 
					    throw error;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const sendMessage = async (message: Message) => {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    const [newMessage] = await db.insert(schema.messages).values({
 | 
				
			||||||
 | 
					      senderId: message.senderId,
 | 
				
			||||||
 | 
					      receiverId: message.receiverId,
 | 
				
			||||||
 | 
					      text: message.text,
 | 
				
			||||||
 | 
					      hasLocation: message.hasLocation,
 | 
				
			||||||
 | 
					      hasMedia: message.hasMedia,
 | 
				
			||||||
 | 
					      hasQuickReply: message.hasQuickReply,
 | 
				
			||||||
 | 
					    }).returning();
 | 
				
			||||||
 | 
					    return newMessage as Message;
 | 
				
			||||||
 | 
					  } catch (error) {
 | 
				
			||||||
 | 
					    console.error('Error sending message:', error);
 | 
				
			||||||
 | 
					    throw error;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user