init. moved lil website for madeline into fuse project so I can write apis in here
This commit is contained in:
		
							
								
								
									
										21
									
								
								src/app/api/getCountdown/route.ts
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										21
									
								
								src/app/api/getCountdown/route.ts
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
'use server';
 | 
			
		||||
import { NextResponse } from 'next/server';
 | 
			
		||||
import { getCountdown } from '~/server/functions';
 | 
			
		||||
 | 
			
		||||
export const GET = async (request: Request) => {
 | 
			
		||||
  try {
 | 
			
		||||
    const url = new URL(request.url);
 | 
			
		||||
    const apiKey = url.searchParams.get('apiKey');
 | 
			
		||||
    if (apiKey !== process.env.API_KEY) {
 | 
			
		||||
      console.log('Invalid API Key');
 | 
			
		||||
      return NextResponse.json({ message: "Invalid API Key" }, { status: 401 });
 | 
			
		||||
    } else {
 | 
			
		||||
      const countdown = await getCountdown();
 | 
			
		||||
      return NextResponse.json(countdown);
 | 
			
		||||
    }
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error(error);
 | 
			
		||||
    return NextResponse.json({ message: "Error" }, { status: 500 });
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
// localhost:3000/api/getCountdown?apiKey=I_Love_Madeline
 | 
			
		||||
							
								
								
									
										22
									
								
								src/app/api/getMessage/route.ts
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										22
									
								
								src/app/api/getMessage/route.ts
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
'use server';
 | 
			
		||||
import { NextResponse } from 'next/server';
 | 
			
		||||
import { getMessage } from '~/server/functions';
 | 
			
		||||
 | 
			
		||||
export const GET = async (request: Request) => {
 | 
			
		||||
  try {
 | 
			
		||||
    const url = new URL(request.url);
 | 
			
		||||
    const apiKey = url.searchParams.get('apiKey');
 | 
			
		||||
    if (apiKey !== process.env.API_KEY) {
 | 
			
		||||
      console.log('Invalid API Key');
 | 
			
		||||
      return NextResponse.json({ message: "Invalid API Key" }, { status: 401 });
 | 
			
		||||
    } else {
 | 
			
		||||
      const userId = url.searchParams.get('userId') ?? '2';
 | 
			
		||||
      const message = await getMessage(parseInt(userId));
 | 
			
		||||
      return NextResponse.json(message);
 | 
			
		||||
    }
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error(error);
 | 
			
		||||
    return NextResponse.json({ message: "Error" }, { status: 500 });
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
// localhost:3000/api/getMessage?apiKey=I_Love_Madeline&userId=2
 | 
			
		||||
							
								
								
									
										23
									
								
								src/app/api/setCountdown/route.ts
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										23
									
								
								src/app/api/setCountdown/route.ts
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
"use server";
 | 
			
		||||
import { NextResponse } from "next/server";
 | 
			
		||||
import type { NextRequest } from "next/server";
 | 
			
		||||
import { setCountdown } from "~/server/functions";
 | 
			
		||||
 | 
			
		||||
export const POST = async (request: NextRequest) => {
 | 
			
		||||
  try {
 | 
			
		||||
    const url = new URL(request.url);
 | 
			
		||||
    const apiKey = url.searchParams.get("apiKey");
 | 
			
		||||
    if (apiKey !== process.env.API_KEY) {
 | 
			
		||||
      console.log("Invalid API Key");
 | 
			
		||||
      return NextResponse.json({ message: "Invalid API Key" }, { status: 401 });
 | 
			
		||||
    } else {
 | 
			
		||||
      const countdown = url.searchParams.get("countdown") ?? "2023-01-01T00:00:00.000Z";
 | 
			
		||||
      await setCountdown(new Date(countdown));
 | 
			
		||||
      return NextResponse.json({ message: "Countdown set successfully" });
 | 
			
		||||
    }
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error(error);
 | 
			
		||||
    return NextResponse.json({ message: "Error" }, { status: 500 });
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
// localhost:3000/api/setCountdown?apiKey=I_Love_Madeline&countdown=2023-01-01T00:00:00.000Z
 | 
			
		||||
							
								
								
									
										24
									
								
								src/app/api/setMessage/route.ts
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										24
									
								
								src/app/api/setMessage/route.ts
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
"use server";
 | 
			
		||||
import { NextResponse } from "next/server";
 | 
			
		||||
import type { NextRequest } from "next/server";
 | 
			
		||||
import { setMessage } from "~/server/functions";
 | 
			
		||||
 | 
			
		||||
export const POST = async (request: NextRequest) => {
 | 
			
		||||
  try {
 | 
			
		||||
    const url = new URL(request.url);
 | 
			
		||||
    const apiKey = url.searchParams.get("apiKey");
 | 
			
		||||
    if (apiKey !== process.env.API_KEY) {
 | 
			
		||||
      console.log("Invalid API Key");
 | 
			
		||||
      return NextResponse.json({ message: "Invalid API Key" }, { status: 401 });
 | 
			
		||||
    } else {
 | 
			
		||||
      const userId = url.searchParams.get("userId") ?? "2";
 | 
			
		||||
      const message = url.searchParams.get("message") ?? "Test";
 | 
			
		||||
      await setMessage(parseInt(userId), message);
 | 
			
		||||
      return NextResponse.json({ message: "Message set successfully" });
 | 
			
		||||
    }
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error(error);
 | 
			
		||||
    return NextResponse.json({ message: "Error" }, { status: 500 });
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
// localhost:3000/api/setMessage?apiKey=I_Love_Madeline&userId=2&message=HelloWorld
 | 
			
		||||
							
								
								
									
										20
									
								
								src/app/layout.tsx
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										20
									
								
								src/app/layout.tsx
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
import "~/styles/globals.css";
 | 
			
		||||
 | 
			
		||||
import { GeistSans } from "geist/font/sans";
 | 
			
		||||
import { type Metadata } from "next";
 | 
			
		||||
 | 
			
		||||
export const metadata: Metadata = {
 | 
			
		||||
  title: "Is Madeline the Cutest?",
 | 
			
		||||
  description: "Answering the easiest question in the world!",
 | 
			
		||||
  icons: [{ rel: "icon", url: "/favicon.png" }],
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default function RootLayout({
 | 
			
		||||
  children,
 | 
			
		||||
}: Readonly<{ children: React.ReactNode }>) {
 | 
			
		||||
  return (
 | 
			
		||||
    <html lang="en" className={`${GeistSans.variable}`}>
 | 
			
		||||
      <body>{children}</body>
 | 
			
		||||
    </html>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										35
									
								
								src/app/page.tsx
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										35
									
								
								src/app/page.tsx
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
"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() {
 | 
			
		||||
  const [currentText, setCurrentText] = useState("");
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    setCurrentText(interestingYes() ?? "Absolutely, yes.");
 | 
			
		||||
  }, []);
 | 
			
		||||
  const handleClick = () => {
 | 
			
		||||
    setCurrentText(interestingYes() ?? "Absolutely, yes.");
 | 
			
		||||
  };
 | 
			
		||||
  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">
 | 
			
		||||
      <h3 className="text-5xl font-extrabold tracking-tight
 | 
			
		||||
        text-white sm:text-[5rem] text-center" onClick={handleClick}>
 | 
			
		||||
        {currentText}
 | 
			
		||||
      </h3>
 | 
			
		||||
    </main>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										46
									
								
								src/env.js
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										46
									
								
								src/env.js
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
import { createEnv } from "@t3-oss/env-nextjs";
 | 
			
		||||
import { z } from "zod";
 | 
			
		||||
 | 
			
		||||
export const env = createEnv({
 | 
			
		||||
  /**
 | 
			
		||||
   * Specify your server-side environment variables schema here. This way you can ensure the app
 | 
			
		||||
   * isn't built with invalid env vars.
 | 
			
		||||
   */
 | 
			
		||||
  server: {
 | 
			
		||||
    DATABASE_URL: z.string().url(),
 | 
			
		||||
    API_KEY: z.string(),
 | 
			
		||||
    NODE_ENV: z
 | 
			
		||||
      .enum(["development", "test", "production"])
 | 
			
		||||
      .default("development"),
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Specify your client-side environment variables schema here. This way you can ensure the app
 | 
			
		||||
   * isn't built with invalid env vars. To expose them to the client, prefix them with
 | 
			
		||||
   * `NEXT_PUBLIC_`.
 | 
			
		||||
   */
 | 
			
		||||
  client: {
 | 
			
		||||
    // NEXT_PUBLIC_CLIENTVAR: z.string(),
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * You can't destruct `process.env` as a regular object in the Next.js edge runtimes (e.g.
 | 
			
		||||
   * middlewares) or client-side so we need to destruct manually.
 | 
			
		||||
   */
 | 
			
		||||
  runtimeEnv: {
 | 
			
		||||
    DATABASE_URL: process.env.DATABASE_URL,
 | 
			
		||||
    API_KEY: process.env.API_KEY,
 | 
			
		||||
    NODE_ENV: process.env.NODE_ENV,
 | 
			
		||||
    // NEXT_PUBLIC_CLIENTVAR: process.env.NEXT_PUBLIC_CLIENTVAR,
 | 
			
		||||
  },
 | 
			
		||||
  /**
 | 
			
		||||
   * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially
 | 
			
		||||
   * useful for Docker builds.
 | 
			
		||||
   */
 | 
			
		||||
  skipValidation: !!process.env.SKIP_ENV_VALIDATION,
 | 
			
		||||
  /**
 | 
			
		||||
   * Makes it so that empty strings are treated as undefined. `SOME_VAR: z.string()` and
 | 
			
		||||
   * `SOME_VAR=''` will throw an error.
 | 
			
		||||
   */
 | 
			
		||||
  emptyStringAsUndefined: true,
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										18
									
								
								src/server/db/index.ts
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										18
									
								
								src/server/db/index.ts
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
import { drizzle } from "drizzle-orm/postgres-js";
 | 
			
		||||
import postgres from "postgres";
 | 
			
		||||
 | 
			
		||||
import { env } from "~/env";
 | 
			
		||||
import * as schema from "./schema";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Cache the database connection in development. This avoids creating a new connection on every HMR
 | 
			
		||||
 * update.
 | 
			
		||||
 */
 | 
			
		||||
const globalForDb = globalThis as unknown as {
 | 
			
		||||
  conn: postgres.Sql | undefined;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const conn = globalForDb.conn ?? postgres(env.DATABASE_URL);
 | 
			
		||||
if (env.NODE_ENV !== "production") globalForDb.conn = conn;
 | 
			
		||||
 | 
			
		||||
export const db = drizzle(conn, { schema });
 | 
			
		||||
							
								
								
									
										29
									
								
								src/server/db/schema.ts
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										29
									
								
								src/server/db/schema.ts
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
import { sql } from "drizzle-orm";
 | 
			
		||||
import {
 | 
			
		||||
  pgTableCreator,
 | 
			
		||||
  serial,
 | 
			
		||||
  timestamp,
 | 
			
		||||
  varchar,
 | 
			
		||||
} from "drizzle-orm/pg-core";
 | 
			
		||||
 | 
			
		||||
export const createTable = pgTableCreator((name) => `${name}`);
 | 
			
		||||
 | 
			
		||||
export const users = createTable(
 | 
			
		||||
  "user",
 | 
			
		||||
  {
 | 
			
		||||
    id: serial("id").primaryKey(),
 | 
			
		||||
    name: varchar("name", { length: 256 }),
 | 
			
		||||
    message: varchar("message", { length: 256 }),
 | 
			
		||||
    createdAt: timestamp("created_at", { withTimezone: true })
 | 
			
		||||
      .default(sql`CURRENT_TIMESTAMP`)
 | 
			
		||||
      .notNull(),
 | 
			
		||||
  },
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export const countdown = createTable(
 | 
			
		||||
  "countdown",
 | 
			
		||||
  {
 | 
			
		||||
    id: serial("id").primaryKey(),
 | 
			
		||||
    date: timestamp("date", { withTimezone: true }),
 | 
			
		||||
  },
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										55
									
								
								src/server/functions.ts
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										55
									
								
								src/server/functions.ts
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
import 'server-only';
 | 
			
		||||
import { db } from '~/server/db';
 | 
			
		||||
import * as schema from '~/server/db/schema';
 | 
			
		||||
import { eq } from 'drizzle-orm';
 | 
			
		||||
 | 
			
		||||
export const getMessage = async (userId: number) => {
 | 
			
		||||
  try {
 | 
			
		||||
    let message = 1;
 | 
			
		||||
    if (userId === 1)
 | 
			
		||||
      message = 2;
 | 
			
		||||
    const result = await db.select({
 | 
			
		||||
      receivedMessage: schema.users.message,
 | 
			
		||||
    }).from(schema.users)
 | 
			
		||||
    .where(eq(schema.users.id, message))
 | 
			
		||||
    return result;
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error("Error fetching message", error);
 | 
			
		||||
    throw new Error("Failed to fetch message");
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const setMessage = async (userId: number, message: string) => {
 | 
			
		||||
  try {
 | 
			
		||||
    await db.update(schema.users)
 | 
			
		||||
      .set({ message: message })
 | 
			
		||||
      .where(eq(schema.users.id, userId));
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error("Error setting message", error);
 | 
			
		||||
    throw new Error("Failed to set message");
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const getCountdown = async () => {
 | 
			
		||||
  try {
 | 
			
		||||
    const result = await db.select({
 | 
			
		||||
      countdown: schema.countdown.date,
 | 
			
		||||
    }).from(schema.countdown)
 | 
			
		||||
    .where(eq(schema.countdown.id, 1))
 | 
			
		||||
    return result;
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error("Error fetching countdown", error);
 | 
			
		||||
    throw new Error("Failed to fetch countdown");
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const setCountdown = async (date: Date) => {
 | 
			
		||||
  try {
 | 
			
		||||
    await db.update(schema.countdown)
 | 
			
		||||
      .set({ date: date })
 | 
			
		||||
      .where(eq(schema.countdown.id, 1));
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error("Error setting countdown", error);
 | 
			
		||||
    throw new Error("Failed to set countdown");
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										3
									
								
								src/styles/globals.css
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										3
									
								
								src/styles/globals.css
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
@tailwind base;
 | 
			
		||||
@tailwind components;
 | 
			
		||||
@tailwind utilities;
 | 
			
		||||
		Reference in New Issue
	
	Block a user