Skip to content

Commit

Permalink
chore: sync main branch
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremyphilemon committed Jan 23, 2025
1 parent 512f052 commit 5705b6a
Show file tree
Hide file tree
Showing 139 changed files with 17,211 additions and 6,125 deletions.
8 changes: 3 additions & 5 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ OPENAI_API_KEY=****
# Generate a random secret: https://generate-secret.vercel.app/32 or `openssl rand -base64 32`
AUTH_SECRET=****

/*
* The following keys below are automatically created and
* added to your environment when you deploy on vercel
*/
# The following keys below are automatically created and
# added to your environment when you deploy on vercel

# Instructions to create kv database here: https://vercel.com/docs/storage/vercel-blob
# Instructions to create a Vercel Blob Store here: https://vercel.com/docs/storage/vercel-blob
BLOB_READ_WRITE_TOKEN=****

# Instructions to create a database here: https://vercel.com/docs/storage/vercel-postgres/quickstart
Expand Down
23 changes: 2 additions & 21 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,10 @@
"prettier",
"plugin:tailwindcss/recommended"
],
"plugins": ["import", "tailwindcss"],
"plugins": ["tailwindcss"],
"rules": {
"tailwindcss/no-custom-classname": "off",
"tailwindcss/classnames-order": "off",
"import/order": [
"error",
{
"groups": [
"builtin",
"external",
"internal",
["parent", "sibling"],
"index",
"object",
"type"
],
"newlines-between": "always",
"alphabetize": {
"order": "asc",
"caseInsensitive": true
}
}
]
"tailwindcss/classnames-order": "off"
},
"settings": {
"import/resolver": {
Expand Down
25 changes: 25 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Lint
on:
push:

jobs:
build:
runs-on: ubuntu-22.04
strategy:
matrix:
node-version: [20]
steps:
- uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- name: Run lint
run: pnpm lint
8 changes: 0 additions & 8 deletions ai/index.ts

This file was deleted.

63 changes: 31 additions & 32 deletions app/(auth)/actions.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
"use server";
'use server';

import { z } from "zod";
import { z } from 'zod';

import { createUser, getUser } from "@/db/queries";
import { createUser, getUser } from '@/lib/db/queries';

import { signIn } from "./auth";
import { signIn } from './auth';

const authFormSchema = z.object({
email: z.string().email(),
password: z.string().min(6),
});

export interface LoginActionState {
status: "idle" | "in_progress" | "success" | "failed" | "invalid_data";
status: 'idle' | 'in_progress' | 'success' | 'failed' | 'invalid_data';
}

export const login = async (
Expand All @@ -21,34 +21,34 @@ export const login = async (
): Promise<LoginActionState> => {
try {
const validatedData = authFormSchema.parse({
email: formData.get("email"),
password: formData.get("password"),
email: formData.get('email'),
password: formData.get('password'),
});

await signIn("credentials", {
await signIn('credentials', {
email: validatedData.email,
password: validatedData.password,
redirect: false,
});

return { status: "success" };
return { status: 'success' };
} catch (error) {
if (error instanceof z.ZodError) {
return { status: "invalid_data" };
return { status: 'invalid_data' };
}

return { status: "failed" };
return { status: 'failed' };
}
};

export interface RegisterActionState {
status:
| "idle"
| "in_progress"
| "success"
| "failed"
| "user_exists"
| "invalid_data";
| 'idle'
| 'in_progress'
| 'success'
| 'failed'
| 'user_exists'
| 'invalid_data';
}

export const register = async (
Expand All @@ -57,29 +57,28 @@ export const register = async (
): Promise<RegisterActionState> => {
try {
const validatedData = authFormSchema.parse({
email: formData.get("email"),
password: formData.get("password"),
email: formData.get('email'),
password: formData.get('password'),
});

let [user] = await getUser(validatedData.email);
const [user] = await getUser(validatedData.email);

if (user) {
return { status: "user_exists" } as RegisterActionState;
} else {
await createUser(validatedData.email, validatedData.password);
await signIn("credentials", {
email: validatedData.email,
password: validatedData.password,
redirect: false,
});

return { status: "success" };
return { status: 'user_exists' } as RegisterActionState;
}
await createUser(validatedData.email, validatedData.password);
await signIn('credentials', {
email: validatedData.email,
password: validatedData.password,
redirect: false,
});

return { status: 'success' };
} catch (error) {
if (error instanceof z.ZodError) {
return { status: "invalid_data" };
return { status: 'invalid_data' };
}

return { status: "failed" };
return { status: 'failed' };
}
};
2 changes: 1 addition & 1 deletion app/(auth)/api/auth/[...nextauth]/route.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { GET, POST } from "@/app/(auth)/auth";
export { GET, POST } from '@/app/(auth)/auth';
14 changes: 7 additions & 7 deletions app/(auth)/auth.config.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { NextAuthConfig } from "next-auth";
import type { NextAuthConfig } from 'next-auth';

export const authConfig = {
pages: {
signIn: "/login",
newUser: "/",
signIn: '/login',
newUser: '/',
},
providers: [
// added later in auth.ts since it requires bcrypt which is only compatible with Node.js
Expand All @@ -12,12 +12,12 @@ export const authConfig = {
callbacks: {
authorized({ auth, request: { nextUrl } }) {
let isLoggedIn = !!auth?.user;
let isOnChat = nextUrl.pathname.startsWith("/");
let isOnRegister = nextUrl.pathname.startsWith("/register");
let isOnLogin = nextUrl.pathname.startsWith("/login");
// let isOnChat = nextUrl.pathname.startsWith("/");
let isOnRegister = nextUrl.pathname.startsWith('/register');
let isOnLogin = nextUrl.pathname.startsWith('/login');

if (isLoggedIn && (isOnLogin || isOnRegister)) {
return Response.redirect(new URL("/", nextUrl));
return Response.redirect(new URL('/', nextUrl as unknown as URL));
}

if (isOnRegister || isOnLogin) {
Expand Down
18 changes: 10 additions & 8 deletions app/(auth)/auth.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { compare } from "bcrypt-ts";
import NextAuth, { User, Session } from "next-auth";
import Credentials from "next-auth/providers/credentials";
import { compare } from 'bcrypt-ts';
import NextAuth, { type User, type Session } from 'next-auth';
import Credentials from 'next-auth/providers/credentials';

import { getUser } from "@/db/queries";
import { getUser } from '@/lib/db/queries';

import { authConfig } from "./auth.config";
import { authConfig } from './auth.config';

interface ExtendedSession extends Session {
user: User;
Expand All @@ -21,10 +21,12 @@ export const {
Credentials({
credentials: {},
async authorize({ email, password }: any) {
let users = await getUser(email);
const users = await getUser(email);
if (users.length === 0) return null;
let passwordsMatch = await compare(password, users[0].password!);
if (passwordsMatch) return users[0] as any;
// biome-ignore lint: Forbidden non-null assertion.
const passwordsMatch = await compare(password, users[0].password!);
if (!passwordsMatch) return null;
return users[0] as any;
},
}),
],
Expand Down
40 changes: 21 additions & 19 deletions app/(auth)/login/page.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,46 @@
"use client";
'use client';

import Link from "next/link";
import { useRouter } from "next/navigation";
import { useActionState, useEffect, useState } from "react";
import { toast } from "sonner";
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import { useActionState, useEffect, useState } from 'react';
import { toast } from 'sonner';

import { AuthForm } from "@/components/custom/auth-form";
import { SubmitButton } from "@/components/custom/submit-button";
import { AuthForm } from '@/components/auth-form';
import { SubmitButton } from '@/components/submit-button';

import { login, LoginActionState } from "../actions";
import { login, type LoginActionState } from '../actions';

export default function Page() {
const router = useRouter();

const [email, setEmail] = useState("");
const [email, setEmail] = useState('');
const [isSuccessful, setIsSuccessful] = useState(false);

const [state, formAction] = useActionState<LoginActionState, FormData>(
login,
{
status: "idle",
status: 'idle',
},
);

useEffect(() => {
if (state.status === "failed") {
toast.error("Invalid credentials!");
} else if (state.status === "invalid_data") {
toast.error("Failed validating your submission!");
} else if (state.status === "success") {
if (state.status === 'failed') {
toast.error('Invalid credentials!');
} else if (state.status === 'invalid_data') {
toast.error('Failed validating your submission!');
} else if (state.status === 'success') {
setIsSuccessful(true);
router.refresh();
}
}, [state.status, router]);

const handleSubmit = (formData: FormData) => {
setEmail(formData.get("email") as string);
setEmail(formData.get('email') as string);
formAction(formData);
};

return (
<div className="flex h-screen w-screen items-center justify-center bg-background">
<div className="flex h-dvh w-screen items-start pt-12 md:pt-0 md:items-center justify-center bg-background">
<div className="w-full max-w-md overflow-hidden rounded-2xl flex flex-col gap-12">
<div className="flex flex-col items-center justify-center gap-2 px-4 text-center sm:px-16">
<h3 className="text-xl font-semibold dark:text-zinc-50">Sign In</h3>
Expand All @@ -47,7 +49,7 @@ export default function Page() {
</p>
</div>
<AuthForm action={handleSubmit} defaultEmail={email}>
<SubmitButton>Sign in</SubmitButton>
<SubmitButton isSuccessful={isSuccessful}>Sign in</SubmitButton>
<p className="text-center text-sm text-gray-600 mt-4 dark:text-zinc-400">
{"Don't have an account? "}
<Link
Expand All @@ -56,7 +58,7 @@ export default function Page() {
>
Sign up
</Link>
{" for free."}
{' for free.'}
</p>
</AuthForm>
</div>
Expand Down
Loading

0 comments on commit 5705b6a

Please sign in to comment.