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