prettier setup

This commit is contained in:
Om Lanke
2025-06-30 11:55:48 +05:30
parent 99220fb9a9
commit ba6ee585dc
63 changed files with 3950 additions and 2115 deletions

View File

@@ -1,10 +1,10 @@
// This configuration only applies to the package manager root. // This configuration only applies to the package manager root.
/** @type {import("eslint").Linter.Config} */ /** @type {import("eslint").Linter.Config} */
module.exports = { module.exports = {
ignorePatterns: ["apps/**", "packages/**"], ignorePatterns: ['apps/**', 'packages/**'],
extends: ["@workspace/eslint-config/library.js"], extends: ['@workspace/eslint-config/library.js'],
parser: "@typescript-eslint/parser", parser: '@typescript-eslint/parser',
parserOptions: { parserOptions: {
project: true, project: true,
}, },
} };

11
.prettierignore Normal file
View File

@@ -0,0 +1,11 @@
node_modules/
build/
dist/
.next/
out/
coverage/
.DS_Store
pnpm-lock.yaml
*.env
*.log
.turbo/

8
.prettierrc Normal file
View File

@@ -0,0 +1,8 @@
{
"semi": true,
"singleQuote": true,
"trailingComma": "all",
"printWidth": 100,
"tabWidth": 2,
"endOfLine": "lf"
}

View File

@@ -1,3 +1,5 @@
{ {
"tailwindCSS.experimental.configFile": "packages/ui/src/styles/globals.css" "tailwindCSS.experimental.configFile": "packages/ui/src/styles/globals.css",
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
} }

View File

@@ -27,5 +27,5 @@ Your `tailwind.config.ts` and `globals.css` are already set up to use the compon
To use the components in your app, import them from the `ui` package. To use the components in your app, import them from the `ui` package.
```tsx ```tsx
import { Button } from "@workspace/ui/components/button" import { Button } from '@workspace/ui/components/button';
``` ```

View File

@@ -1,2 +1,2 @@
import { handlers } from "@workspace/auth"; import { handlers } from '@workspace/auth';
export const { GET, POST } = handlers; export const { GET, POST } = handlers;

View File

@@ -1,121 +1,119 @@
import localFont from "next/font/local" import localFont from 'next/font/local';
import "@workspace/ui/globals.css" import '@workspace/ui/globals.css';
import { Providers } from "@/components/providers" import { Providers } from '@/components/providers';
const firaSans = localFont({ const firaSans = localFont({
src: [ src: [
{ {
path: "../fonts/Fira-sans/FiraSans-Thin.ttf", path: '../fonts/Fira-sans/FiraSans-Thin.ttf',
weight: "100", weight: '100',
style: "normal", style: 'normal',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-ThinItalic.ttf", path: '../fonts/Fira-sans/FiraSans-ThinItalic.ttf',
weight: "100", weight: '100',
style: "italic", style: 'italic',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-ExtraLight.ttf", path: '../fonts/Fira-sans/FiraSans-ExtraLight.ttf',
weight: "200", weight: '200',
style: "normal", style: 'normal',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-ExtraLightItalic.ttf", path: '../fonts/Fira-sans/FiraSans-ExtraLightItalic.ttf',
weight: "200", weight: '200',
style: "italic", style: 'italic',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-Light.ttf", path: '../fonts/Fira-sans/FiraSans-Light.ttf',
weight: "300", weight: '300',
style: "normal", style: 'normal',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-LightItalic.ttf", path: '../fonts/Fira-sans/FiraSans-LightItalic.ttf',
weight: "300", weight: '300',
style: "italic", style: 'italic',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-Regular.ttf", path: '../fonts/Fira-sans/FiraSans-Regular.ttf',
weight: "400", weight: '400',
style: "normal", style: 'normal',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-Italic.ttf", path: '../fonts/Fira-sans/FiraSans-Italic.ttf',
weight: "400", weight: '400',
style: "italic", style: 'italic',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-Medium.ttf", path: '../fonts/Fira-sans/FiraSans-Medium.ttf',
weight: "500", weight: '500',
style: "normal", style: 'normal',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-MediumItalic.ttf", path: '../fonts/Fira-sans/FiraSans-MediumItalic.ttf',
weight: "500", weight: '500',
style: "italic", style: 'italic',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-SemiBold.ttf", path: '../fonts/Fira-sans/FiraSans-SemiBold.ttf',
weight: "600", weight: '600',
style: "normal", style: 'normal',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-SemiBoldItalic.ttf", path: '../fonts/Fira-sans/FiraSans-SemiBoldItalic.ttf',
weight: "600", weight: '600',
style: "italic", style: 'italic',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-Bold.ttf", path: '../fonts/Fira-sans/FiraSans-Bold.ttf',
weight: "700", weight: '700',
style: "normal", style: 'normal',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-BoldItalic.ttf", path: '../fonts/Fira-sans/FiraSans-BoldItalic.ttf',
weight: "700", weight: '700',
style: "italic", style: 'italic',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-ExtraBold.ttf", path: '../fonts/Fira-sans/FiraSans-ExtraBold.ttf',
weight: "800", weight: '800',
style: "normal", style: 'normal',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-ExtraBoldItalic.ttf", path: '../fonts/Fira-sans/FiraSans-ExtraBoldItalic.ttf',
weight: "800", weight: '800',
style: "italic", style: 'italic',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-Black.ttf", path: '../fonts/Fira-sans/FiraSans-Black.ttf',
weight: "900", weight: '900',
style: "normal", style: 'normal',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-BlackItalic.ttf", path: '../fonts/Fira-sans/FiraSans-BlackItalic.ttf',
weight: "900", weight: '900',
style: "italic", style: 'italic',
}, },
], ],
variable: "--font-sans", variable: '--font-sans',
}) });
const marcellus = localFont({ const marcellus = localFont({
src: "../fonts/Marcellus/Marcellus-Regular.ttf", src: '../fonts/Marcellus/Marcellus-Regular.ttf',
variable: "--font-marcellus", variable: '--font-marcellus',
}) });
export default function RootLayout({ export default function RootLayout({
children, children,
}: Readonly<{ }: Readonly<{
children: React.ReactNode children: React.ReactNode;
}>) { }>) {
return ( return (
<html lang="en" suppressHydrationWarning> <html lang="en" suppressHydrationWarning>
<body <body className={`${firaSans.variable} ${marcellus.variable} font-sans antialiased `}>
className={`${firaSans.variable} ${marcellus.variable} font-sans antialiased `}
>
<Providers>{children}</Providers> <Providers>{children}</Providers>
</body> </body>
</html> </html>
) );
} }

View File

@@ -1,21 +1,21 @@
import Login from "@/components/login"; import Login from '@/components/login';
import Studs from "@/components/studs"; import Studs from '@/components/studs';
import { db, admins } from "@workspace/db"; import { db, admins } from '@workspace/db';
import { auth, signIn, signOut } from "@workspace/auth"; import { auth, signIn, signOut } from '@workspace/auth';
async function getStudents() { async function getStudents() {
"use server"; 'use server';
const s = await db.select().from(admins); const s = await db.select().from(admins);
console.log(s); console.log(s);
} }
async function logIn() { async function logIn() {
"use server"; 'use server';
await signIn("google"); await signIn('google');
} }
async function logOut() { async function logOut() {
"use server"; 'use server';
await signOut(); await signOut();
} }
@@ -24,9 +24,7 @@ export default async function Page() {
return ( return (
<div className="flex items-center justify-center min-h-svh"> <div className="flex items-center justify-center min-h-svh">
<div className="flex flex-col items-center justify-center gap-4"> <div className="flex flex-col items-center justify-center gap-4">
<h1 className="text-2xl font-bold"> <h1 className="text-2xl font-bold">Hello admin {session?.user?.name}</h1>
Hello admin {session?.user?.name}
</h1>
{!session?.user && <Login action={logIn} />} {!session?.user && <Login action={logIn} />}
<Studs action={getStudents} logOut={logOut} /> <Studs action={getStudents} logOut={logOut} />
</div> </div>

View File

@@ -1,6 +1,6 @@
"use client"; 'use client';
import { signIn } from "@workspace/auth"; import { signIn } from '@workspace/auth';
import { Button } from "@workspace/ui/components/button"; import { Button } from '@workspace/ui/components/button';
export default function Login({ action }: { action: () => Promise<void> }) { export default function Login({ action }: { action: () => Promise<void> }) {
return ( return (

View File

@@ -1,16 +1,11 @@
"use client"; 'use client';
import * as React from "react"; import * as React from 'react';
import { ThemeProvider as NextThemesProvider } from "next-themes"; import { ThemeProvider as NextThemesProvider } from 'next-themes';
export function Providers({ children }: { children: React.ReactNode }) { export function Providers({ children }: { children: React.ReactNode }) {
return ( return (
<NextThemesProvider <NextThemesProvider attribute="class" defaultTheme="system" enableSystem enableColorScheme>
attribute="class"
defaultTheme="system"
enableSystem
enableColorScheme
>
{children} {children}
</NextThemesProvider> </NextThemesProvider>
); );

View File

@@ -1,5 +1,5 @@
import { Button } from "@workspace/ui/components/button"; import { Button } from '@workspace/ui/components/button';
import { auth } from "@workspace/auth"; import { auth } from '@workspace/auth';
export default async function Studs({ export default async function Studs({
action, action,
@@ -12,7 +12,9 @@ export default async function Studs({
if (!session?.user) return null; if (!session?.user) return null;
return ( return (
<div className="flex gap-2"> <div className="flex gap-2">
<Button onClick={action} variant="outline">Click me</Button> <Button onClick={action} variant="outline">
Click me
</Button>
<Button onClick={logOut}>Sign Out</Button> <Button onClick={logOut}>Sign Out</Button>
</div> </div>
); );

View File

@@ -1,4 +1,4 @@
import { nextJsConfig } from "@workspace/eslint-config/next-js" import { nextJsConfig } from '@workspace/eslint-config/next-js';
/** @type {import("eslint").Linter.Config} */ /** @type {import("eslint").Linter.Config} */
export default nextJsConfig export default nextJsConfig;

View File

@@ -1,18 +1,18 @@
import { auth } from "@workspace/auth"; import { auth } from '@workspace/auth';
import { NextResponse } from 'next/server'; import { NextResponse } from 'next/server';
export default auth((req: any) => { export default auth((req: any) => {
// If the user is unauthenticated or an admin, allow the request. // If the user is unauthenticated or an admin, allow the request.
if (!req.auth || req.auth.user?.role === "ADMIN") { if (!req.auth || req.auth.user?.role === 'ADMIN') {
return NextResponse.next(); return NextResponse.next();
} }
// Otherwise, redirect to the student app. // Otherwise, redirect to the student app.
const studentUrl = process.env.STUDENT_URL ?? "http://localhost:3000" const studentUrl = process.env.STUDENT_URL ?? 'http://localhost:3000';
return NextResponse.redirect(new URL(studentUrl, req.url)); return NextResponse.redirect(new URL(studentUrl, req.url));
}) as any; }) as any;
export const config = { export const config = {
matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"], matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
} };

View File

@@ -1,18 +1,18 @@
import "next-auth"; import 'next-auth';
declare module "next-auth" { declare module 'next-auth' {
interface Session { interface Session {
user: { user: {
role?: "ADMIN" | "USER"; role?: 'ADMIN' | 'USER';
adminId?: number; adminId?: number;
studentId?: number; studentId?: number;
[key: string]: any; [key: string]: any;
}; };
} }
} }
declare module "next-auth/jwt" { declare module 'next-auth/jwt' {
interface JWT { interface JWT {
role?: "ADMIN" | "USER"; role?: 'ADMIN' | 'USER';
adminId?: number; adminId?: number;
studentId?: number; studentId?: number;
} }

View File

@@ -1,6 +1,6 @@
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
const nextConfig = { const nextConfig = {
transpilePackages: ["@workspace/ui", "@workspace/db", "@workspace/auth"], transpilePackages: ['@workspace/ui', '@workspace/db', '@workspace/auth'],
}; };
export default nextConfig; export default nextConfig;

View File

@@ -12,7 +12,6 @@
"typecheck": "tsc --noEmit" "typecheck": "tsc --noEmit"
}, },
"dependencies": { "dependencies": {
"@hookform/resolvers": "^5.1.1",
"@workspace/auth": "workspace:*", "@workspace/auth": "workspace:*",
"@workspace/db": "workspace:*", "@workspace/db": "workspace:*",
"@workspace/ui": "workspace:*", "@workspace/ui": "workspace:*",
@@ -22,9 +21,7 @@
"next-auth": "^4.24.11", "next-auth": "^4.24.11",
"next-themes": "^0.4.4", "next-themes": "^0.4.4",
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^19.0.0", "react-dom": "^19.0.0"
"react-hook-form": "^7.58.1",
"zod": "^3.24.2"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20", "@types/node": "^20",

View File

@@ -1 +1 @@
export { default } from "@workspace/ui/postcss.config"; export { default } from '@workspace/ui/postcss.config';

View File

@@ -6,7 +6,7 @@
"@/*": ["./*"], "@/*": ["./*"],
"@workspace/ui/*": ["../../packages/ui/src/*"], "@workspace/ui/*": ["../../packages/ui/src/*"],
"@workspace/db/*": ["../../packages/db/src/*"], "@workspace/db/*": ["../../packages/db/src/*"],
"@workspace/auth/*": ["../../packages/auth/src/*"], "@workspace/auth/*": ["../../packages/auth/src/*"]
}, },
"plugins": [ "plugins": [
{ {
@@ -14,12 +14,6 @@
} }
] ]
}, },
"include": [ "include": ["next-env.d.ts", "next.config.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"next-env.d.ts",
"next.config.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts"
],
"exclude": ["node_modules"] "exclude": ["node_modules"]
} }

View File

@@ -1,2 +1,2 @@
import { handlers } from "@workspace/auth"; import { handlers } from '@workspace/auth';
export const { GET, POST } = handlers; export const { GET, POST } = handlers;

View File

@@ -1,121 +1,119 @@
import localFont from "next/font/local" import localFont from 'next/font/local';
import "@workspace/ui/globals.css" import '@workspace/ui/globals.css';
import { Providers } from "@/components/providers" import { Providers } from '@/components/providers';
const firaSans = localFont({ const firaSans = localFont({
src: [ src: [
{ {
path: "../fonts/Fira-sans/FiraSans-Thin.ttf", path: '../fonts/Fira-sans/FiraSans-Thin.ttf',
weight: "100", weight: '100',
style: "normal", style: 'normal',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-ThinItalic.ttf", path: '../fonts/Fira-sans/FiraSans-ThinItalic.ttf',
weight: "100", weight: '100',
style: "italic", style: 'italic',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-ExtraLight.ttf", path: '../fonts/Fira-sans/FiraSans-ExtraLight.ttf',
weight: "200", weight: '200',
style: "normal", style: 'normal',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-ExtraLightItalic.ttf", path: '../fonts/Fira-sans/FiraSans-ExtraLightItalic.ttf',
weight: "200", weight: '200',
style: "italic", style: 'italic',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-Light.ttf", path: '../fonts/Fira-sans/FiraSans-Light.ttf',
weight: "300", weight: '300',
style: "normal", style: 'normal',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-LightItalic.ttf", path: '../fonts/Fira-sans/FiraSans-LightItalic.ttf',
weight: "300", weight: '300',
style: "italic", style: 'italic',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-Regular.ttf", path: '../fonts/Fira-sans/FiraSans-Regular.ttf',
weight: "400", weight: '400',
style: "normal", style: 'normal',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-Italic.ttf", path: '../fonts/Fira-sans/FiraSans-Italic.ttf',
weight: "400", weight: '400',
style: "italic", style: 'italic',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-Medium.ttf", path: '../fonts/Fira-sans/FiraSans-Medium.ttf',
weight: "500", weight: '500',
style: "normal", style: 'normal',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-MediumItalic.ttf", path: '../fonts/Fira-sans/FiraSans-MediumItalic.ttf',
weight: "500", weight: '500',
style: "italic", style: 'italic',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-SemiBold.ttf", path: '../fonts/Fira-sans/FiraSans-SemiBold.ttf',
weight: "600", weight: '600',
style: "normal", style: 'normal',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-SemiBoldItalic.ttf", path: '../fonts/Fira-sans/FiraSans-SemiBoldItalic.ttf',
weight: "600", weight: '600',
style: "italic", style: 'italic',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-Bold.ttf", path: '../fonts/Fira-sans/FiraSans-Bold.ttf',
weight: "700", weight: '700',
style: "normal", style: 'normal',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-BoldItalic.ttf", path: '../fonts/Fira-sans/FiraSans-BoldItalic.ttf',
weight: "700", weight: '700',
style: "italic", style: 'italic',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-ExtraBold.ttf", path: '../fonts/Fira-sans/FiraSans-ExtraBold.ttf',
weight: "800", weight: '800',
style: "normal", style: 'normal',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-ExtraBoldItalic.ttf", path: '../fonts/Fira-sans/FiraSans-ExtraBoldItalic.ttf',
weight: "800", weight: '800',
style: "italic", style: 'italic',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-Black.ttf", path: '../fonts/Fira-sans/FiraSans-Black.ttf',
weight: "900", weight: '900',
style: "normal", style: 'normal',
}, },
{ {
path: "../fonts/Fira-sans/FiraSans-BlackItalic.ttf", path: '../fonts/Fira-sans/FiraSans-BlackItalic.ttf',
weight: "900", weight: '900',
style: "italic", style: 'italic',
}, },
], ],
variable: "--font-sans", variable: '--font-sans',
}) });
const marcellus = localFont({ const marcellus = localFont({
src: "../fonts/Marcellus/Marcellus-Regular.ttf", src: '../fonts/Marcellus/Marcellus-Regular.ttf',
variable: "--font-marcellus", variable: '--font-marcellus',
}) });
export default function RootLayout({ export default function RootLayout({
children, children,
}: Readonly<{ }: Readonly<{
children: React.ReactNode children: React.ReactNode;
}>) { }>) {
return ( return (
<html lang="en" suppressHydrationWarning> <html lang="en" suppressHydrationWarning>
<body <body className={`${firaSans.variable} ${marcellus.variable} font-sans antialiased `}>
className={`${firaSans.variable} ${marcellus.variable} font-sans antialiased `}
>
<Providers>{children}</Providers> <Providers>{children}</Providers>
</body> </body>
</html> </html>
) );
} }

View File

@@ -1,26 +1,26 @@
import Login from "@/components/login"; import Login from '@/components/login';
import Studs from "@/components/studs"; import Studs from '@/components/studs';
import { db, admins } from "@workspace/db"; import { db, admins } from '@workspace/db';
import { auth, signIn, signOut } from "@workspace/auth"; import { auth, signIn, signOut } from '@workspace/auth';
async function getStudents() { async function getStudents() {
"use server"; 'use server';
const s = await db.select().from(admins); const s = await db.select().from(admins);
console.log(s); console.log(s);
} }
async function logIn() { async function logIn() {
"use server"; 'use server';
await signIn("google"); await signIn('google');
} }
async function logOut() { async function logOut() {
"use server"; 'use server';
await signOut(); await signOut();
} }
export default async function Page() { export default async function Page() {
const session = await auth() const session = await auth();
return ( return (
<div className="flex items-center justify-center min-h-svh"> <div className="flex items-center justify-center min-h-svh">
<div className="flex flex-col items-center justify-center gap-4"> <div className="flex flex-col items-center justify-center gap-4">

View File

@@ -1,151 +1,176 @@
"use client" 'use client';
import { useState } from "react" import { useState } from 'react';
import { useForm } from "react-hook-form" import { useForm } from 'react-hook-form';
import { zodResolver } from "@hookform/resolvers/zod" import { zodResolver } from '@hookform/resolvers/zod';
import * as z from "zod" import * as z from 'zod';
import { Button } from "@workspace/ui/components/button" import { Button } from '@workspace/ui/components/button';
import { Input } from "@workspace/ui/components/input" import { Input } from '@workspace/ui/components/input';
import { Textarea } from "@workspace/ui/components/textarea" import { Textarea } from '@workspace/ui/components/textarea';
import { Progress } from "@workspace/ui/components/progress" import { Progress } from '@workspace/ui/components/progress';
import { Separator } from "@workspace/ui/components/separator" import { Separator } from '@workspace/ui/components/separator';
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, FormDescription } from "@workspace/ui/components/form" import {
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@workspace/ui/components/select" Form,
import { Card, CardContent, CardHeader, CardTitle } from "@workspace/ui/components/card" FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
FormDescription,
} from '@workspace/ui/components/form';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@workspace/ui/components/select';
import { Card, CardContent, CardHeader, CardTitle } from '@workspace/ui/components/card';
// Form schema // Form schema
const formSchema = z.object({ const formSchema = z.object({
// Personal Details // Personal Details
firstName: z.string().min(1, "First name is required"), firstName: z.string().min(1, 'First name is required'),
lastName: z.string().min(1, "Last name is required"), lastName: z.string().min(1, 'Last name is required'),
fathersName: z.string().optional(), fathersName: z.string().optional(),
mothersName: z.string().optional(), mothersName: z.string().optional(),
email: z.string().email("Invalid email address"), email: z.string().email('Invalid email address'),
rollNumber: z.string().min(1, "Roll number is required"), rollNumber: z.string().min(1, 'Roll number is required'),
phoneNumber: z.string().min(10, "Phone number must be at least 10 digits"), phoneNumber: z.string().min(10, 'Phone number must be at least 10 digits'),
address: z.string().min(1, "Address is required"), address: z.string().min(1, 'Address is required'),
// Academic Details // Academic Details
degree: z.string().min(1, "Degree is required"), degree: z.string().min(1, 'Degree is required'),
year: z.string().min(1, "Year is required"), year: z.string().min(1, 'Year is required'),
branch: z.string().min(1, "Branch is required"), branch: z.string().min(1, 'Branch is required'),
ssc: z.string().min(1, "SSC percentage is required"), ssc: z.string().min(1, 'SSC percentage is required'),
hsc: z.string().min(1, "HSC percentage is required"), hsc: z.string().min(1, 'HSC percentage is required'),
// Semester Grades // Semester Grades
sem1: z.string().min(1, "Semester 1 grade is required"), sem1: z.string().min(1, 'Semester 1 grade is required'),
sem1KT: z.string().min(1, "Semester 1 KT status is required"), sem1KT: z.string().min(1, 'Semester 1 KT status is required'),
sem2: z.string().min(1, "Semester 2 grade is required"), sem2: z.string().min(1, 'Semester 2 grade is required'),
sem2KT: z.string().min(1, "Semester 2 KT status is required"), sem2KT: z.string().min(1, 'Semester 2 KT status is required'),
// Additional Details // Additional Details
linkedin: z.string().url("Invalid LinkedIn URL"), linkedin: z.string().url('Invalid LinkedIn URL'),
github: z.string().url("Invalid GitHub URL"), github: z.string().url('Invalid GitHub URL'),
skills: z.string().optional(), skills: z.string().optional(),
}) });
type FormData = z.infer<typeof formSchema> type FormData = z.infer<typeof formSchema>;
const steps = [ const steps = [
{ {
id: 1, id: 1,
title: "Personal Details", title: 'Personal Details',
fields: ["firstName", "lastName", "fathersName", "mothersName", "email", "rollNumber", "phoneNumber", "address"], fields: [
'firstName',
'lastName',
'fathersName',
'mothersName',
'email',
'rollNumber',
'phoneNumber',
'address',
],
}, },
{ id: 2, title: "Academic Details", fields: ["degree", "year", "branch", "ssc", "hsc"] }, { id: 2, title: 'Academic Details', fields: ['degree', 'year', 'branch', 'ssc', 'hsc'] },
{ id: 3, title: "Semester Grades", fields: ["sem1", "sem1KT", "sem2", "sem2KT"] }, { id: 3, title: 'Semester Grades', fields: ['sem1', 'sem1KT', 'sem2', 'sem2KT'] },
{ id: 4, title: "Additional Details", fields: ["linkedin", "github", "skills"] }, { id: 4, title: 'Additional Details', fields: ['linkedin', 'github', 'skills'] },
] ];
export default function StudentRegistrationForm() { export default function StudentRegistrationForm() {
const [currentStep, setCurrentStep] = useState(1) const [currentStep, setCurrentStep] = useState(1);
const [isSubmitting, setIsSubmitting] = useState(false) const [isSubmitting, setIsSubmitting] = useState(false);
const form = useForm<FormData>({ const form = useForm<FormData>({
resolver: zodResolver(formSchema), resolver: zodResolver(formSchema),
defaultValues: { defaultValues: {
firstName: "", firstName: '',
lastName: "", lastName: '',
fathersName: "", fathersName: '',
mothersName: "", mothersName: '',
email: "", email: '',
rollNumber: "", rollNumber: '',
phoneNumber: "", phoneNumber: '',
address: "", address: '',
degree: "", degree: '',
year: "", year: '',
branch: "", branch: '',
ssc: "", ssc: '',
hsc: "", hsc: '',
sem1: "", sem1: '',
sem1KT: "", sem1KT: '',
sem2: "", sem2: '',
sem2KT: "", sem2KT: '',
linkedin: "", linkedin: '',
github: "", github: '',
skills: "", skills: '',
}, },
}) });
const validateCurrentStep = async () => { const validateCurrentStep = async () => {
const currentStepData = steps.find((step) => step.id === currentStep) const currentStepData = steps.find((step) => step.id === currentStep);
if (!currentStepData) return false if (!currentStepData) return false;
const result = await form.trigger(currentStepData.fields as any) const result = await form.trigger(currentStepData.fields as any);
return result return result;
} };
const nextStep = async () => { const nextStep = async () => {
const isValid = await validateCurrentStep() const isValid = await validateCurrentStep();
if (isValid && currentStep < steps.length) { if (isValid && currentStep < steps.length) {
setCurrentStep(currentStep + 1) setCurrentStep(currentStep + 1);
} }
} };
const prevStep = () => { const prevStep = () => {
if (currentStep > 1) { if (currentStep > 1) {
setCurrentStep(currentStep - 1) setCurrentStep(currentStep - 1);
} }
} };
const onSubmit = async (data: FormData) => { const onSubmit = async (data: FormData) => {
setIsSubmitting(true) setIsSubmitting(true);
try { try {
// Simulate API call // Simulate API call
await new Promise((resolve) => setTimeout(resolve, 2000)) await new Promise((resolve) => setTimeout(resolve, 2000));
console.log("Form submitted:", data) console.log('Form submitted:', data);
alert("Form submitted successfully!") alert('Form submitted successfully!');
} catch (error) { } catch (error) {
console.error("Submission error:", error) console.error('Submission error:', error);
alert("Submission failed. Please try again.") alert('Submission failed. Please try again.');
} finally { } finally {
setIsSubmitting(false) setIsSubmitting(false);
} }
} };
const renderStep = () => { const renderStep = () => {
switch (currentStep) { switch (currentStep) {
case 1: case 1:
return <PersonalDetailsStep form={form} /> return <PersonalDetailsStep form={form} />;
case 2: case 2:
return <AcademicDetailsStep form={form} /> return <AcademicDetailsStep form={form} />;
case 3: case 3:
return <SemesterGradesStep form={form} /> return <SemesterGradesStep form={form} />;
case 4: case 4:
return <AdditionalDetailsStep form={form} /> return <AdditionalDetailsStep form={form} />;
default: default:
return null return null;
} }
} };
const progress = (currentStep / steps.length) * 100 const progress = (currentStep / steps.length) * 100;
return ( return (
<div className="min-h-screen py-8"> <div className="min-h-screen py-8">
<div className="max-w-3xl mx-auto px-4"> <div className="max-w-3xl mx-auto px-4">
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle className="text-2xl font-bold text-center">Student Registration Form</CardTitle> <CardTitle className="text-2xl font-bold text-center">
Student Registration Form
</CardTitle>
<div className="space-y-2"> <div className="space-y-2">
<div className="flex justify-between text-sm text-muted-foreground"> <div className="flex justify-between text-sm text-muted-foreground">
<span> <span>
@@ -162,13 +187,18 @@ export default function StudentRegistrationForm() {
{renderStep()} {renderStep()}
<div className="flex justify-between pt-6"> <div className="flex justify-between pt-6">
<Button type="button" variant="outline" onClick={prevStep} disabled={currentStep === 1}> <Button
type="button"
variant="outline"
onClick={prevStep}
disabled={currentStep === 1}
>
Previous Previous
</Button> </Button>
{currentStep === steps.length ? ( {currentStep === steps.length ? (
<Button type="submit" disabled={isSubmitting}> <Button type="submit" disabled={isSubmitting}>
{isSubmitting ? "Submitting..." : "Submit"} {isSubmitting ? 'Submitting...' : 'Submit'}
</Button> </Button>
) : ( ) : (
<Button type="button" onClick={nextStep}> <Button type="button" onClick={nextStep}>
@@ -182,7 +212,7 @@ export default function StudentRegistrationForm() {
</Card> </Card>
</div> </div>
</div> </div>
) );
} }
function PersonalDetailsStep({ form }: { form: any }) { function PersonalDetailsStep({ form }: { form: any }) {
@@ -308,30 +338,30 @@ function PersonalDetailsStep({ form }: { form: any }) {
)} )}
/> />
</div> </div>
) );
} }
function AcademicDetailsStep({ form }: { form: any }) { function AcademicDetailsStep({ form }: { form: any }) {
const degreeOptions = [ const degreeOptions = [
{ value: "btech", label: "B.Tech" }, { value: 'btech', label: 'B.Tech' },
{ value: "be", label: "B.E." }, { value: 'be', label: 'B.E.' },
{ value: "bsc", label: "B.Sc" }, { value: 'bsc', label: 'B.Sc' },
{ value: "bca", label: "BCA" }, { value: 'bca', label: 'BCA' },
] ];
const yearOptions = [ const yearOptions = [
{ value: "2024", label: "2024" }, { value: '2024', label: '2024' },
{ value: "2025", label: "2025" }, { value: '2025', label: '2025' },
{ value: "2026", label: "2026" }, { value: '2026', label: '2026' },
{ value: "2027", label: "2027" }, { value: '2027', label: '2027' },
] ];
const branchOptions = [ const branchOptions = [
{ value: "cse", label: "Computer Science" }, { value: 'cse', label: 'Computer Science' },
{ value: "it", label: "Information Technology" }, { value: 'it', label: 'Information Technology' },
{ value: "ece", label: "Electronics & Communication" }, { value: 'ece', label: 'Electronics & Communication' },
{ value: "mechanical", label: "Mechanical" }, { value: 'mechanical', label: 'Mechanical' },
] ];
return ( return (
<div className="space-y-4"> <div className="space-y-4">
@@ -443,16 +473,16 @@ function AcademicDetailsStep({ form }: { form: any }) {
/> />
</div> </div>
</div> </div>
) );
} }
function SemesterGradesStep({ form }: { form: any }) { function SemesterGradesStep({ form }: { form: any }) {
const ktOptions = [ const ktOptions = [
{ value: "0", label: "0 KT" }, { value: '0', label: '0 KT' },
{ value: "1", label: "1 KT" }, { value: '1', label: '1 KT' },
{ value: "2", label: "2 KT" }, { value: '2', label: '2 KT' },
{ value: "3+", label: "3+ KT" }, { value: '3+', label: '3+ KT' },
] ];
return ( return (
<div className="space-y-4"> <div className="space-y-4">
@@ -538,7 +568,7 @@ function SemesterGradesStep({ form }: { form: any }) {
/> />
</div> </div>
</div> </div>
) );
} }
function AdditionalDetailsStep({ form }: { form: any }) { function AdditionalDetailsStep({ form }: { form: any }) {
@@ -594,5 +624,5 @@ function AdditionalDetailsStep({ form }: { form: any }) {
)} )}
/> />
</div> </div>
) );
} }

View File

@@ -1,24 +1,20 @@
"use client"; 'use client';
import { signIn } from "@workspace/auth"; import { signIn } from '@workspace/auth';
import { Button } from "@workspace/ui/components/button"; import { Button } from '@workspace/ui/components/button';
export default function Login({logIn}: {logIn: () => Promise<void>}) { export default function Login({ logIn }: { logIn: () => Promise<void> }) {
return ( return (
<form action={logIn}> <form action={logIn}>
<Button <Button type="submit" variant="outline" className="w-full h-12">
type="submit" <div className="absolute inset-0 bg-gradient-to-r from-primary/0 via-primary/10 to-primary/0 translate-x-[-100%] group-hover:translate-x-[100%] transition-transform duration-700 ease-out pointer-events-none" />
variant="outline" <img
className="w-full h-12" src="https://static.cdnlogo.com/logos/g/35/google-icon.svg"
> alt="Google logo"
<div className="absolute inset-0 bg-gradient-to-r from-primary/0 via-primary/10 to-primary/0 translate-x-[-100%] group-hover:translate-x-[100%] transition-transform duration-700 ease-out pointer-events-none" /> className="w-5 h-5 transition-transform duration-200"
<img />
src="https://static.cdnlogo.com/logos/g/35/google-icon.svg" <span className="relative z-10 font-medium transition-colors duration-200 group-hover:text-foreground">
alt="Google logo" Sign in with Google
className="w-5 h-5 transition-transform duration-200" </span>
/>
<span className="relative z-10 font-medium transition-colors duration-200 group-hover:text-foreground">
Sign in with Google
</span>
</Button> </Button>
</form> </form>
); );

View File

@@ -1,16 +1,11 @@
"use client"; 'use client';
import * as React from "react"; import * as React from 'react';
import { ThemeProvider as NextThemesProvider } from "next-themes"; import { ThemeProvider as NextThemesProvider } from 'next-themes';
export function Providers({ children }: { children: React.ReactNode }) { export function Providers({ children }: { children: React.ReactNode }) {
return ( return (
<NextThemesProvider <NextThemesProvider attribute="class" defaultTheme="system" enableSystem enableColorScheme>
attribute="class"
defaultTheme="system"
enableSystem
enableColorScheme
>
{children} {children}
</NextThemesProvider> </NextThemesProvider>
); );

View File

@@ -1,5 +1,5 @@
import { Button } from "@workspace/ui/components/button"; import { Button } from '@workspace/ui/components/button';
import { auth } from "@workspace/auth"; import { auth } from '@workspace/auth';
export default async function Studs({ export default async function Studs({
action, action,
@@ -12,7 +12,9 @@ export default async function Studs({
if (!session?.user) return null; if (!session?.user) return null;
return ( return (
<div className="flex gap-2"> <div className="flex gap-2">
<Button onClick={action} variant="outline">Click me</Button> <Button onClick={action} variant="outline">
Click me
</Button>
<Button onClick={logOut}>Sign Out</Button> <Button onClick={logOut}>Sign Out</Button>
</div> </div>
); );

View File

@@ -1,4 +1,4 @@
import { nextJsConfig } from "@workspace/eslint-config/next-js" import { nextJsConfig } from '@workspace/eslint-config/next-js';
/** @type {import("eslint").Linter.Config} */ /** @type {import("eslint").Linter.Config} */
export default nextJsConfig export default nextJsConfig;

View File

@@ -1,18 +1,18 @@
import { auth } from "@workspace/auth"; import { auth } from '@workspace/auth';
import { NextResponse } from 'next/server'; import { NextResponse } from 'next/server';
export default auth((req: any) => { export default auth((req: any) => {
// If the user is unauthenticated or a student, allow the request. // If the user is unauthenticated or a student, allow the request.
if (!req.auth || req.auth.user?.role === "USER") { if (!req.auth || req.auth.user?.role === 'USER') {
return NextResponse.next(); return NextResponse.next();
} }
// Otherwise, redirect to the admin app. // Otherwise, redirect to the admin app.
const adminURL = process.env.ADMIN_URL ?? "http://localhost:3001" const adminURL = process.env.ADMIN_URL ?? 'http://localhost:3001';
return NextResponse.redirect(new URL(adminURL, req.url)); return NextResponse.redirect(new URL(adminURL, req.url));
}) as any; }) as any;
export const config = { export const config = {
matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"], matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
} };

View File

@@ -1,9 +1,9 @@
import "next-auth"; import 'next-auth';
declare module "next-auth" { declare module 'next-auth' {
interface Session { interface Session {
user: { user: {
role?: "ADMIN" | "USER"; role?: 'ADMIN' | 'USER';
adminId?: number; adminId?: number;
studentId?: number; studentId?: number;
[key: string]: any; [key: string]: any;
@@ -11,9 +11,9 @@ declare module "next-auth" {
} }
} }
declare module "next-auth/jwt" { declare module 'next-auth/jwt' {
interface JWT { interface JWT {
role?: "ADMIN" | "USER"; role?: 'ADMIN' | 'USER';
adminId?: number; adminId?: number;
studentId?: number; studentId?: number;
} }

View File

@@ -1,6 +1,6 @@
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
const nextConfig = { const nextConfig = {
transpilePackages: ["@workspace/ui", "@workspace/auth", "@workspace/db"], transpilePackages: ['@workspace/ui', '@workspace/auth', '@workspace/db'],
}; };
export default nextConfig; export default nextConfig;

View File

@@ -12,6 +12,7 @@
"typecheck": "tsc --noEmit" "typecheck": "tsc --noEmit"
}, },
"dependencies": { "dependencies": {
"@hookform/resolvers": "^5.1.1",
"@workspace/ui": "workspace:*", "@workspace/ui": "workspace:*",
"@workspace/db": "workspace:*", "@workspace/db": "workspace:*",
"@workspace/auth": "workspace:*", "@workspace/auth": "workspace:*",
@@ -20,7 +21,9 @@
"next-auth": "^4.24.11", "next-auth": "^4.24.11",
"next-themes": "^0.4.4", "next-themes": "^0.4.4",
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^19.0.0" "react-dom": "^19.0.0",
"react-hook-form": "^7.58.1",
"zod": "^3.24.2"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20", "@types/node": "^20",

View File

@@ -1 +1 @@
export { default } from "@workspace/ui/postcss.config"; export { default } from '@workspace/ui/postcss.config';

View File

@@ -14,12 +14,6 @@
} }
] ]
}, },
"include": [ "include": ["next-env.d.ts", "next.config.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"next-env.d.ts",
"next.config.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts"
],
"exclude": ["node_modules"] "exclude": ["node_modules"]
} }

View File

@@ -1,7 +1,7 @@
import NextAuth, { type NextAuthConfig } from "next-auth"; import NextAuth, { type NextAuthConfig } from 'next-auth';
import Google from "next-auth/providers/google"; import Google from 'next-auth/providers/google';
import { db, admins, students } from "@workspace/db"; import { db, admins, students } from '@workspace/db';
import { eq } from "drizzle-orm"; import { eq } from 'drizzle-orm';
const authConfig: NextAuthConfig = { const authConfig: NextAuthConfig = {
providers: [Google], providers: [Google],
@@ -9,16 +9,12 @@ const authConfig: NextAuthConfig = {
async jwt({ token, account, user, profile }) { async jwt({ token, account, user, profile }) {
// Only check DB on first sign in // Only check DB on first sign in
if (account && user && user.email) { if (account && user && user.email) {
const admin = await db const admin = await db.select().from(admins).where(eq(admins.email, user.email)).limit(1);
.select()
.from(admins)
.where(eq(admins.email, user.email))
.limit(1);
if (admin.length > 0 && admin[0]) { if (admin.length > 0 && admin[0]) {
token.role = "ADMIN"; token.role = 'ADMIN';
token.adminId = admin[0].id; token.adminId = admin[0].id;
} else { } else {
token.role = "USER"; token.role = 'USER';
const student = await db const student = await db
.select() .select()
.from(students) .from(students)
@@ -27,9 +23,9 @@ const authConfig: NextAuthConfig = {
if (student.length > 0 && student[0]) { if (student.length > 0 && student[0]) {
token.studentId = student[0].id; token.studentId = student[0].id;
} else { } else {
const nameParts = user.name?.split(" ") ?? []; const nameParts = user.name?.split(' ') ?? [];
const firstName = nameParts[0] || ""; const firstName = nameParts[0] || '';
const lastName = nameParts.slice(1).join(" ") || ""; const lastName = nameParts.slice(1).join(' ') || '';
const newStudent = await db const newStudent = await db
.insert(students) .insert(students)
.values({ .values({
@@ -49,7 +45,7 @@ const authConfig: NextAuthConfig = {
}, },
async session({ session, token }) { async session({ session, token }) {
if (token?.role) { if (token?.role) {
session.user.role = token.role as "ADMIN" | "USER"; session.user.role = token.role as 'ADMIN' | 'USER';
} }
if (token?.adminId) { if (token?.adminId) {
session.user.adminId = token.adminId as number; session.user.adminId = token.adminId as number;

View File

@@ -1,19 +1,19 @@
import "next-auth"; import 'next-auth';
import "next-auth/jwt"; import 'next-auth/jwt';
declare module "next-auth" { declare module 'next-auth' {
interface Session { interface Session {
user: { user: {
role?: "ADMIN" | "USER"; role?: 'ADMIN' | 'USER';
adminId?: number; adminId?: number;
studentId?: number; studentId?: number;
[key: string]: any; [key: string]: any;
}; };
} }
} }
declare module "next-auth/jwt" { declare module 'next-auth/jwt' {
interface JWT { interface JWT {
role?: "ADMIN" | "USER"; role?: 'ADMIN' | 'USER';
adminId?: number; adminId?: number;
studentId?: number; studentId?: number;
} }

View File

@@ -1,12 +1,12 @@
import { config } from "dotenv"; import { config } from 'dotenv';
import { defineConfig } from "drizzle-kit"; import { defineConfig } from 'drizzle-kit';
config({ path: "../../.env" }); config({ path: '../../.env' });
export default defineConfig({ export default defineConfig({
schema: "./schema.ts", schema: './schema.ts',
out: "./migrations", out: './migrations',
dialect: "postgresql", dialect: 'postgresql',
dbCredentials: { dbCredentials: {
url: process.env.DATABASE_URL!, url: process.env.DATABASE_URL!,
}, },

View File

@@ -1,5 +1,5 @@
import { drizzle } from "drizzle-orm/neon-http"; import { drizzle } from 'drizzle-orm/neon-http';
export const db = drizzle(process.env.DATABASE_URL!); export const db = drizzle(process.env.DATABASE_URL!);
export * from "./schema"; export * from './schema';

View File

@@ -60,12 +60,8 @@
"name": "applications_job_id_jobs_id_fk", "name": "applications_job_id_jobs_id_fk",
"tableFrom": "applications", "tableFrom": "applications",
"tableTo": "jobs", "tableTo": "jobs",
"columnsFrom": [ "columnsFrom": ["job_id"],
"job_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -73,12 +69,8 @@
"name": "applications_student_id_students_id_fk", "name": "applications_student_id_students_id_fk",
"tableFrom": "applications", "tableFrom": "applications",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -86,12 +78,8 @@
"name": "applications_resume_id_resumes_id_fk", "name": "applications_resume_id_resumes_id_fk",
"tableFrom": "applications", "tableFrom": "applications",
"tableTo": "resumes", "tableTo": "resumes",
"columnsFrom": [ "columnsFrom": ["resume_id"],
"resume_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -157,12 +145,8 @@
"name": "certificates_student_id_students_id_fk", "name": "certificates_student_id_students_id_fk",
"tableFrom": "certificates", "tableFrom": "certificates",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -303,12 +287,8 @@
"name": "grades_student_id_students_id_fk", "name": "grades_student_id_students_id_fk",
"tableFrom": "grades", "tableFrom": "grades",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -398,12 +378,8 @@
"name": "internships_student_id_students_id_fk", "name": "internships_student_id_students_id_fk",
"tableFrom": "internships", "tableFrom": "internships",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -535,12 +511,8 @@
"name": "jobs_company_id_companies_id_fk", "name": "jobs_company_id_companies_id_fk",
"tableFrom": "jobs", "tableFrom": "jobs",
"tableTo": "companies", "tableTo": "companies",
"columnsFrom": [ "columnsFrom": ["company_id"],
"company_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -607,12 +579,8 @@
"name": "projects_student_id_students_id_fk", "name": "projects_student_id_students_id_fk",
"tableFrom": "projects", "tableFrom": "projects",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -672,12 +640,8 @@
"name": "resumes_student_id_students_id_fk", "name": "resumes_student_id_students_id_fk",
"tableFrom": "resumes", "tableFrom": "resumes",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }

View File

@@ -60,12 +60,8 @@
"name": "applications_job_id_jobs_id_fk", "name": "applications_job_id_jobs_id_fk",
"tableFrom": "applications", "tableFrom": "applications",
"tableTo": "jobs", "tableTo": "jobs",
"columnsFrom": [ "columnsFrom": ["job_id"],
"job_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -73,12 +69,8 @@
"name": "applications_student_id_students_id_fk", "name": "applications_student_id_students_id_fk",
"tableFrom": "applications", "tableFrom": "applications",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -86,12 +78,8 @@
"name": "applications_resume_id_resumes_id_fk", "name": "applications_resume_id_resumes_id_fk",
"tableFrom": "applications", "tableFrom": "applications",
"tableTo": "resumes", "tableTo": "resumes",
"columnsFrom": [ "columnsFrom": ["resume_id"],
"resume_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -157,12 +145,8 @@
"name": "certificates_student_id_students_id_fk", "name": "certificates_student_id_students_id_fk",
"tableFrom": "certificates", "tableFrom": "certificates",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -303,12 +287,8 @@
"name": "grades_student_id_students_id_fk", "name": "grades_student_id_students_id_fk",
"tableFrom": "grades", "tableFrom": "grades",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -398,12 +378,8 @@
"name": "internships_student_id_students_id_fk", "name": "internships_student_id_students_id_fk",
"tableFrom": "internships", "tableFrom": "internships",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -535,12 +511,8 @@
"name": "jobs_company_id_companies_id_fk", "name": "jobs_company_id_companies_id_fk",
"tableFrom": "jobs", "tableFrom": "jobs",
"tableTo": "companies", "tableTo": "companies",
"columnsFrom": [ "columnsFrom": ["company_id"],
"company_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -607,12 +579,8 @@
"name": "projects_student_id_students_id_fk", "name": "projects_student_id_students_id_fk",
"tableFrom": "projects", "tableFrom": "projects",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -672,12 +640,8 @@
"name": "resumes_student_id_students_id_fk", "name": "resumes_student_id_students_id_fk",
"tableFrom": "resumes", "tableFrom": "resumes",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }

View File

@@ -42,9 +42,7 @@
"admins_email_unique": { "admins_email_unique": {
"name": "admins_email_unique", "name": "admins_email_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["email"]
"email"
]
} }
}, },
"policies": {}, "policies": {},
@@ -107,12 +105,8 @@
"name": "applications_job_id_jobs_id_fk", "name": "applications_job_id_jobs_id_fk",
"tableFrom": "applications", "tableFrom": "applications",
"tableTo": "jobs", "tableTo": "jobs",
"columnsFrom": [ "columnsFrom": ["job_id"],
"job_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -120,12 +114,8 @@
"name": "applications_student_id_students_id_fk", "name": "applications_student_id_students_id_fk",
"tableFrom": "applications", "tableFrom": "applications",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -133,12 +123,8 @@
"name": "applications_resume_id_resumes_id_fk", "name": "applications_resume_id_resumes_id_fk",
"tableFrom": "applications", "tableFrom": "applications",
"tableTo": "resumes", "tableTo": "resumes",
"columnsFrom": [ "columnsFrom": ["resume_id"],
"resume_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -204,12 +190,8 @@
"name": "certificates_student_id_students_id_fk", "name": "certificates_student_id_students_id_fk",
"tableFrom": "certificates", "tableFrom": "certificates",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -350,12 +332,8 @@
"name": "grades_student_id_students_id_fk", "name": "grades_student_id_students_id_fk",
"tableFrom": "grades", "tableFrom": "grades",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -445,12 +423,8 @@
"name": "internships_student_id_students_id_fk", "name": "internships_student_id_students_id_fk",
"tableFrom": "internships", "tableFrom": "internships",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -582,12 +556,8 @@
"name": "jobs_company_id_companies_id_fk", "name": "jobs_company_id_companies_id_fk",
"tableFrom": "jobs", "tableFrom": "jobs",
"tableTo": "companies", "tableTo": "companies",
"columnsFrom": [ "columnsFrom": ["company_id"],
"company_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -654,12 +624,8 @@
"name": "projects_student_id_students_id_fk", "name": "projects_student_id_students_id_fk",
"tableFrom": "projects", "tableFrom": "projects",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -719,12 +685,8 @@
"name": "resumes_student_id_students_id_fk", "name": "resumes_student_id_students_id_fk",
"tableFrom": "resumes", "tableFrom": "resumes",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }

View File

@@ -42,9 +42,7 @@
"admins_email_unique": { "admins_email_unique": {
"name": "admins_email_unique", "name": "admins_email_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["email"]
"email"
]
} }
}, },
"policies": {}, "policies": {},
@@ -107,12 +105,8 @@
"name": "applications_job_id_jobs_id_fk", "name": "applications_job_id_jobs_id_fk",
"tableFrom": "applications", "tableFrom": "applications",
"tableTo": "jobs", "tableTo": "jobs",
"columnsFrom": [ "columnsFrom": ["job_id"],
"job_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -120,12 +114,8 @@
"name": "applications_student_id_students_id_fk", "name": "applications_student_id_students_id_fk",
"tableFrom": "applications", "tableFrom": "applications",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -133,12 +123,8 @@
"name": "applications_resume_id_resumes_id_fk", "name": "applications_resume_id_resumes_id_fk",
"tableFrom": "applications", "tableFrom": "applications",
"tableTo": "resumes", "tableTo": "resumes",
"columnsFrom": [ "columnsFrom": ["resume_id"],
"resume_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -204,12 +190,8 @@
"name": "certificates_student_id_students_id_fk", "name": "certificates_student_id_students_id_fk",
"tableFrom": "certificates", "tableFrom": "certificates",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -344,12 +326,8 @@
"name": "grades_student_id_students_id_fk", "name": "grades_student_id_students_id_fk",
"tableFrom": "grades", "tableFrom": "grades",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -357,10 +335,7 @@
"compositePrimaryKeys": { "compositePrimaryKeys": {
"grades_student_id_sem_pk": { "grades_student_id_sem_pk": {
"name": "grades_student_id_sem_pk", "name": "grades_student_id_sem_pk",
"columns": [ "columns": ["student_id", "sem"]
"student_id",
"sem"
]
} }
}, },
"uniqueConstraints": {}, "uniqueConstraints": {},
@@ -452,12 +427,8 @@
"name": "internships_student_id_students_id_fk", "name": "internships_student_id_students_id_fk",
"tableFrom": "internships", "tableFrom": "internships",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -589,12 +560,8 @@
"name": "jobs_company_id_companies_id_fk", "name": "jobs_company_id_companies_id_fk",
"tableFrom": "jobs", "tableFrom": "jobs",
"tableTo": "companies", "tableTo": "companies",
"columnsFrom": [ "columnsFrom": ["company_id"],
"company_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -661,12 +628,8 @@
"name": "projects_student_id_students_id_fk", "name": "projects_student_id_students_id_fk",
"tableFrom": "projects", "tableFrom": "projects",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -726,12 +689,8 @@
"name": "resumes_student_id_students_id_fk", "name": "resumes_student_id_students_id_fk",
"tableFrom": "resumes", "tableFrom": "resumes",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }

View File

@@ -42,9 +42,7 @@
"admins_email_unique": { "admins_email_unique": {
"name": "admins_email_unique", "name": "admins_email_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["email"]
"email"
]
} }
}, },
"policies": {}, "policies": {},
@@ -107,12 +105,8 @@
"name": "applications_job_id_jobs_id_fk", "name": "applications_job_id_jobs_id_fk",
"tableFrom": "applications", "tableFrom": "applications",
"tableTo": "jobs", "tableTo": "jobs",
"columnsFrom": [ "columnsFrom": ["job_id"],
"job_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -120,12 +114,8 @@
"name": "applications_student_id_students_id_fk", "name": "applications_student_id_students_id_fk",
"tableFrom": "applications", "tableFrom": "applications",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -133,12 +123,8 @@
"name": "applications_resume_id_resumes_id_fk", "name": "applications_resume_id_resumes_id_fk",
"tableFrom": "applications", "tableFrom": "applications",
"tableTo": "resumes", "tableTo": "resumes",
"columnsFrom": [ "columnsFrom": ["resume_id"],
"resume_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -267,12 +253,8 @@
"name": "grades_student_id_students_id_fk", "name": "grades_student_id_students_id_fk",
"tableFrom": "grades", "tableFrom": "grades",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -280,10 +262,7 @@
"compositePrimaryKeys": { "compositePrimaryKeys": {
"grades_student_id_sem_pk": { "grades_student_id_sem_pk": {
"name": "grades_student_id_sem_pk", "name": "grades_student_id_sem_pk",
"columns": [ "columns": ["student_id", "sem"]
"student_id",
"sem"
]
} }
}, },
"uniqueConstraints": {}, "uniqueConstraints": {},
@@ -369,12 +348,8 @@
"name": "internships_student_id_students_id_fk", "name": "internships_student_id_students_id_fk",
"tableFrom": "internships", "tableFrom": "internships",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -506,12 +481,8 @@
"name": "jobs_company_id_companies_id_fk", "name": "jobs_company_id_companies_id_fk",
"tableFrom": "jobs", "tableFrom": "jobs",
"tableTo": "companies", "tableTo": "companies",
"columnsFrom": [ "columnsFrom": ["company_id"],
"company_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -571,12 +542,8 @@
"name": "resumes_student_id_students_id_fk", "name": "resumes_student_id_students_id_fk",
"tableFrom": "resumes", "tableFrom": "resumes",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }

View File

@@ -42,9 +42,7 @@
"admins_email_unique": { "admins_email_unique": {
"name": "admins_email_unique", "name": "admins_email_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["email"]
"email"
]
} }
}, },
"policies": {}, "policies": {},
@@ -107,12 +105,8 @@
"name": "applications_job_id_jobs_id_fk", "name": "applications_job_id_jobs_id_fk",
"tableFrom": "applications", "tableFrom": "applications",
"tableTo": "jobs", "tableTo": "jobs",
"columnsFrom": [ "columnsFrom": ["job_id"],
"job_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -120,12 +114,8 @@
"name": "applications_student_id_students_id_fk", "name": "applications_student_id_students_id_fk",
"tableFrom": "applications", "tableFrom": "applications",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -133,12 +123,8 @@
"name": "applications_resume_id_resumes_id_fk", "name": "applications_resume_id_resumes_id_fk",
"tableFrom": "applications", "tableFrom": "applications",
"tableTo": "resumes", "tableTo": "resumes",
"columnsFrom": [ "columnsFrom": ["resume_id"],
"resume_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -267,12 +253,8 @@
"name": "grades_student_id_students_id_fk", "name": "grades_student_id_students_id_fk",
"tableFrom": "grades", "tableFrom": "grades",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -280,10 +262,7 @@
"compositePrimaryKeys": { "compositePrimaryKeys": {
"grades_student_id_sem_pk": { "grades_student_id_sem_pk": {
"name": "grades_student_id_sem_pk", "name": "grades_student_id_sem_pk",
"columns": [ "columns": ["student_id", "sem"]
"student_id",
"sem"
]
} }
}, },
"uniqueConstraints": {}, "uniqueConstraints": {},
@@ -369,12 +348,8 @@
"name": "internships_student_id_students_id_fk", "name": "internships_student_id_students_id_fk",
"tableFrom": "internships", "tableFrom": "internships",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -506,12 +481,8 @@
"name": "jobs_company_id_companies_id_fk", "name": "jobs_company_id_companies_id_fk",
"tableFrom": "jobs", "tableFrom": "jobs",
"tableTo": "companies", "tableTo": "companies",
"columnsFrom": [ "columnsFrom": ["company_id"],
"company_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -571,12 +542,8 @@
"name": "resumes_student_id_students_id_fk", "name": "resumes_student_id_students_id_fk",
"tableFrom": "resumes", "tableFrom": "resumes",
"tableTo": "students", "tableTo": "students",
"columnsFrom": [ "columnsFrom": ["student_id"],
"student_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }

View File

@@ -1,4 +1,4 @@
import { sql, relations } from "drizzle-orm"; import { sql, relations } from 'drizzle-orm';
import { import {
pgTable, pgTable,
serial, serial,
@@ -10,9 +10,9 @@ import {
numeric, numeric,
primaryKey, primaryKey,
check, check,
} from "drizzle-orm/pg-core"; } from 'drizzle-orm/pg-core';
export const students = pgTable("students", { export const students = pgTable('students', {
id: serial().primaryKey(), id: serial().primaryKey(),
email: text().notNull(), email: text().notNull(),
rollNumber: varchar({ length: 12 }), rollNumber: varchar({ length: 12 }),
@@ -45,9 +45,9 @@ export const students = pgTable("students", {
.notNull(), .notNull(),
}); });
export const internships = pgTable("internships", { export const internships = pgTable('internships', {
id: serial().primaryKey(), id: serial().primaryKey(),
studentId: integer("student_id") studentId: integer('student_id')
.notNull() .notNull()
.references(() => students.id), .references(() => students.id),
title: text().notNull(), title: text().notNull(),
@@ -97,9 +97,9 @@ export const internships = pgTable("internships", {
// .notNull(), // .notNull(),
// }); // });
export const resumes = pgTable("resumes", { export const resumes = pgTable('resumes', {
id: serial().primaryKey(), id: serial().primaryKey(),
studentId: integer("student_id") studentId: integer('student_id')
.notNull() .notNull()
.references(() => students.id), .references(() => students.id),
title: text().notNull(), title: text().notNull(),
@@ -112,9 +112,9 @@ export const resumes = pgTable("resumes", {
}); });
export const grades = pgTable( export const grades = pgTable(
"grades", 'grades',
{ {
studentId: integer("student_id") studentId: integer('student_id')
.notNull() .notNull()
.references(() => students.id), .references(() => students.id),
sem: integer().notNull(), sem: integer().notNull(),
@@ -129,7 +129,7 @@ export const grades = pgTable(
}, },
(table) => [ (table) => [
primaryKey({ columns: [table.studentId, table.sem] }), primaryKey({ columns: [table.studentId, table.sem] }),
check("sem_check1", sql`${table.sem} < 9`), check('sem_check1', sql`${table.sem} < 9`),
], ],
); );
@@ -177,7 +177,7 @@ export const gradeRelations = relations(grades, ({ one }) => ({
}), }),
})); }));
export const companies = pgTable("companies", { export const companies = pgTable('companies', {
id: serial().primaryKey(), id: serial().primaryKey(),
name: text().notNull(), name: text().notNull(),
email: text().notNull(), email: text().notNull(),
@@ -192,9 +192,9 @@ export const companies = pgTable("companies", {
.notNull(), .notNull(),
}); });
export const jobs = pgTable("jobs", { export const jobs = pgTable('jobs', {
id: serial().primaryKey(), id: serial().primaryKey(),
companyId: integer("company_id") companyId: integer('company_id')
.notNull() .notNull()
.references(() => companies.id), .references(() => companies.id),
title: text().notNull(), title: text().notNull(),
@@ -205,9 +205,9 @@ export const jobs = pgTable("jobs", {
salary: text().notNull(), salary: text().notNull(),
applicationDeadline: timestamp().notNull(), applicationDeadline: timestamp().notNull(),
active: boolean().notNull().default(false), active: boolean().notNull().default(false),
minCGPA: numeric({ precision: 4, scale: 2 }).notNull().default("0"), minCGPA: numeric({ precision: 4, scale: 2 }).notNull().default('0'),
minSSC: numeric({ precision: 4, scale: 2 }).notNull().default("0"), minSSC: numeric({ precision: 4, scale: 2 }).notNull().default('0'),
minHSC: numeric({ precision: 4, scale: 2 }).notNull().default("0"), minHSC: numeric({ precision: 4, scale: 2 }).notNull().default('0'),
allowDeadKT: boolean().notNull().default(true), allowDeadKT: boolean().notNull().default(true),
allowLiveKT: boolean().notNull().default(true), allowLiveKT: boolean().notNull().default(true),
createdAt: timestamp().notNull().defaultNow(), createdAt: timestamp().notNull().defaultNow(),
@@ -217,18 +217,18 @@ export const jobs = pgTable("jobs", {
.notNull(), .notNull(),
}); });
export const applications = pgTable("applications", { export const applications = pgTable('applications', {
id: serial().primaryKey(), id: serial().primaryKey(),
jobId: integer("job_id") jobId: integer('job_id')
.notNull() .notNull()
.references(() => jobs.id), .references(() => jobs.id),
studentId: integer("student_id") studentId: integer('student_id')
.notNull() .notNull()
.references(() => students.id), .references(() => students.id),
resumeId: integer("resume_id") resumeId: integer('resume_id')
.notNull() .notNull()
.references(() => resumes.id), .references(() => resumes.id),
status: text().notNull().default("pending"), status: text().notNull().default('pending'),
createdAt: timestamp().notNull().defaultNow(), createdAt: timestamp().notNull().defaultNow(),
updatedAt: timestamp() updatedAt: timestamp()
.defaultNow() .defaultNow()
@@ -263,7 +263,7 @@ export const applicationsRelations = relations(applications, ({ one }) => ({
}), }),
})); }));
export const admins = pgTable("admins", { export const admins = pgTable('admins', {
id: serial().primaryKey(), id: serial().primaryKey(),
email: text().notNull().unique(), email: text().notNull().unique(),
createdAt: timestamp().notNull().defaultNow(), createdAt: timestamp().notNull().defaultNow(),

View File

@@ -1,8 +1,8 @@
import js from "@eslint/js" import js from '@eslint/js';
import eslintConfigPrettier from "eslint-config-prettier" import eslintConfigPrettier from 'eslint-config-prettier';
import onlyWarn from "eslint-plugin-only-warn" import onlyWarn from 'eslint-plugin-only-warn';
import turboPlugin from "eslint-plugin-turbo" import turboPlugin from 'eslint-plugin-turbo';
import tseslint from "typescript-eslint" import tseslint from 'typescript-eslint';
/** /**
* A shared ESLint configuration for the repository. * A shared ESLint configuration for the repository.
@@ -18,7 +18,7 @@ export const config = [
turbo: turboPlugin, turbo: turboPlugin,
}, },
rules: { rules: {
"turbo/no-undeclared-env-vars": "warn", 'turbo/no-undeclared-env-vars': 'warn',
}, },
}, },
{ {
@@ -27,6 +27,6 @@ export const config = [
}, },
}, },
{ {
ignores: ["dist/**"], ignores: ['dist/**'],
}, },
] ];

View File

@@ -1,12 +1,12 @@
import js from "@eslint/js" import js from '@eslint/js';
import pluginNext from "@next/eslint-plugin-next" import pluginNext from '@next/eslint-plugin-next';
import eslintConfigPrettier from "eslint-config-prettier" import eslintConfigPrettier from 'eslint-config-prettier';
import pluginReact from "eslint-plugin-react" import pluginReact from 'eslint-plugin-react';
import pluginReactHooks from "eslint-plugin-react-hooks" import pluginReactHooks from 'eslint-plugin-react-hooks';
import globals from "globals" import globals from 'globals';
import tseslint from "typescript-eslint" import tseslint from 'typescript-eslint';
import { config as baseConfig } from "./base.js" import { config as baseConfig } from './base.js';
/** /**
* A custom ESLint configuration for libraries that use Next.js. * A custom ESLint configuration for libraries that use Next.js.
@@ -29,23 +29,23 @@ export const nextJsConfig = [
}, },
{ {
plugins: { plugins: {
"@next/next": pluginNext, '@next/next': pluginNext,
}, },
rules: { rules: {
...pluginNext.configs.recommended.rules, ...pluginNext.configs.recommended.rules,
...pluginNext.configs["core-web-vitals"].rules, ...pluginNext.configs['core-web-vitals'].rules,
}, },
}, },
{ {
plugins: { plugins: {
"react-hooks": pluginReactHooks, 'react-hooks': pluginReactHooks,
}, },
settings: { react: { version: "detect" } }, settings: { react: { version: 'detect' } },
rules: { rules: {
...pluginReactHooks.configs.recommended.rules, ...pluginReactHooks.configs.recommended.rules,
// React scope no longer necessary with new JSX transform. // React scope no longer necessary with new JSX transform.
"react/react-in-jsx-scope": "off", 'react/react-in-jsx-scope': 'off',
"react/prop-types": "off", 'react/prop-types': 'off',
}, },
}, },
] ];

View File

@@ -1,11 +1,11 @@
import js from "@eslint/js" import js from '@eslint/js';
import eslintConfigPrettier from "eslint-config-prettier" import eslintConfigPrettier from 'eslint-config-prettier';
import pluginReact from "eslint-plugin-react" import pluginReact from 'eslint-plugin-react';
import pluginReactHooks from "eslint-plugin-react-hooks" import pluginReactHooks from 'eslint-plugin-react-hooks';
import globals from "globals" import globals from 'globals';
import tseslint from "typescript-eslint" import tseslint from 'typescript-eslint';
import { config as baseConfig } from "./base.js" import { config as baseConfig } from './base.js';
/** /**
* A custom ESLint configuration for libraries that use React. * A custom ESLint configuration for libraries that use React.
@@ -28,14 +28,14 @@ export const config = [
}, },
{ {
plugins: { plugins: {
"react-hooks": pluginReactHooks, 'react-hooks': pluginReactHooks,
}, },
settings: { react: { version: "detect" } }, settings: { react: { version: 'detect' } },
rules: { rules: {
...pluginReactHooks.configs.recommended.rules, ...pluginReactHooks.configs.recommended.rules,
// React scope no longer necessary with new JSX transform. // React scope no longer necessary with new JSX transform.
"react/react-in-jsx-scope": "off", 'react/react-in-jsx-scope': 'off',
"react/prop-types": "off", 'react/prop-types': 'off',
}, },
}, },
] ];

View File

@@ -1,4 +1,4 @@
import { config } from "@workspace/eslint-config/react-internal" import { config } from '@workspace/eslint-config/react-internal';
/** @type {import("eslint").Linter.Config} */ /** @type {import("eslint").Linter.Config} */
export default config export default config;

View File

@@ -1,6 +1,6 @@
/** @type {import('postcss-load-config').Config} */ /** @type {import('postcss-load-config').Config} */
const config = { const config = {
plugins: { "@tailwindcss/postcss": {} }, plugins: { '@tailwindcss/postcss': {} },
}; };
export default config; export default config;

View File

@@ -1,8 +1,8 @@
import React from "react"; import React from 'react';
import { Slot } from "@radix-ui/react-slot"; import { Slot } from '@radix-ui/react-slot';
import { cva, type VariantProps } from "class-variance-authority"; import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from "@workspace/ui/lib/utils"; import { cn } from '@workspace/ui/lib/utils';
const buttonVariants = cva( const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg text-sm font-medium transition-all duration-200 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-ring hover:scale-105 active:scale-95 transform-gpu", "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg text-sm font-medium transition-all duration-200 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-ring hover:scale-105 active:scale-95 transform-gpu",
@@ -10,29 +10,28 @@ const buttonVariants = cva(
variants: { variants: {
variant: { variant: {
default: default:
"bg-primary text-primary-foreground shadow-lg shadow-primary/25 hover:bg-primary/85 hover:shadow-xl hover:shadow-primary/35", 'bg-primary text-primary-foreground shadow-lg shadow-primary/25 hover:bg-primary/85 hover:shadow-xl hover:shadow-primary/35',
destructive: destructive:
"bg-destructive text-destructive-foreground shadow-lg shadow-destructive/25 hover:bg-destructive/85 hover:shadow-xl hover:shadow-destructive/35", 'bg-destructive text-destructive-foreground shadow-lg shadow-destructive/25 hover:bg-destructive/85 hover:shadow-xl hover:shadow-destructive/35',
outline: outline:
"border-2 border-primary/20 bg-background hover:bg-primary/5 hover:text-primary hover:border-primary/40 shadow-md hover:shadow-lg hover:shadow-primary/15", 'border-2 border-primary/20 bg-background hover:bg-primary/5 hover:text-primary hover:border-primary/40 shadow-md hover:shadow-lg hover:shadow-primary/15',
secondary: secondary:
"bg-secondary text-secondary-foreground shadow-md hover:bg-secondary/80 hover:shadow-lg", 'bg-secondary text-secondary-foreground shadow-md hover:bg-secondary/80 hover:shadow-lg',
ghost: ghost: 'hover:bg-primary/10 hover:text-primary hover:shadow-md hover:shadow-primary/10',
"hover:bg-primary/10 hover:text-primary hover:shadow-md hover:shadow-primary/10", link: 'text-primary underline-offset-4 hover:underline hover:text-accent p-0 h-auto font-normal hover:scale-100 active:scale-100',
link: "text-primary underline-offset-4 hover:underline hover:text-accent p-0 h-auto font-normal hover:scale-100 active:scale-100",
accent: accent:
"bg-accent text-accent-foreground shadow-lg shadow-accent/25 hover:bg-accent/85 hover:shadow-xl hover:shadow-accent/35", 'bg-accent text-accent-foreground shadow-lg shadow-accent/25 hover:bg-accent/85 hover:shadow-xl hover:shadow-accent/35',
}, },
size: { size: {
default: "h-10 px-4 py-2", default: 'h-10 px-4 py-2',
sm: "h-8 rounded-md px-3 text-xs", sm: 'h-8 rounded-md px-3 text-xs',
lg: "h-12 rounded-lg px-6 text-base", lg: 'h-12 rounded-lg px-6 text-base',
icon: "h-10 w-10", icon: 'h-10 w-10',
}, },
}, },
defaultVariants: { defaultVariants: {
variant: "default", variant: 'default',
size: "default", size: 'default',
}, },
}, },
); );
@@ -45,16 +44,12 @@ export interface ButtonProps
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>( const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => { ({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"; const Comp = asChild ? Slot : 'button';
return ( return (
<Comp <Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
); );
}, },
); );
Button.displayName = "Button"; Button.displayName = 'Button';
export { Button, buttonVariants }; export { Button, buttonVariants };

View File

@@ -1,75 +1,78 @@
import type * as React from "react" import type * as React from 'react';
import { cn } from "@workspace/ui/lib/utils" import { cn } from '@workspace/ui/lib/utils';
function Card({ className, ...props }: React.ComponentProps<"div">) { function Card({ className, ...props }: React.ComponentProps<'div'>) {
return ( return (
<div <div
data-slot="card" data-slot="card"
className={cn( className={cn(
"bg-card/90 text-card-foreground flex flex-col gap-6 rounded-2xl border border-border/50 py-8 shadow-xl shadow-black/5 backdrop-blur-sm hover:shadow-2xl hover:shadow-black/10 transition-all duration-300 hover:-translate-y-1", 'bg-card/90 text-card-foreground flex flex-col gap-6 rounded-2xl border border-border/50 py-8 shadow-xl shadow-black/5 backdrop-blur-sm hover:shadow-2xl hover:shadow-black/10 transition-all duration-300 hover:-translate-y-1',
className, className,
)} )}
{...props} {...props}
/> />
) );
} }
function CardHeader({ className, ...props }: React.ComponentProps<"div">) { function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
return ( return (
<div <div
data-slot="card-header" data-slot="card-header"
className={cn( className={cn(
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-3 px-8 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6 [.border-b]:border-border/30", '@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-3 px-8 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6 [.border-b]:border-border/30',
className, className,
)} )}
{...props} {...props}
/> />
) );
} }
function CardTitle({ className, ...props }: React.ComponentProps<"div">) { function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
return ( return (
<div <div
data-slot="card-title" data-slot="card-title"
className={cn("leading-tight font-bold text-lg tracking-tight", className)} className={cn('leading-tight font-bold text-lg tracking-tight', className)}
{...props} {...props}
/> />
) );
} }
function CardDescription({ className, ...props }: React.ComponentProps<"div">) { function CardDescription({ className, ...props }: React.ComponentProps<'div'>) {
return ( return (
<div <div
data-slot="card-description" data-slot="card-description"
className={cn("text-muted-foreground text-sm leading-relaxed", className)} className={cn('text-muted-foreground text-sm leading-relaxed', className)}
{...props} {...props}
/> />
) );
} }
function CardAction({ className, ...props }: React.ComponentProps<"div">) { function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
return ( return (
<div <div
data-slot="card-action" data-slot="card-action"
className={cn("col-start-2 row-span-2 row-start-1 self-start justify-self-end", className)} className={cn('col-start-2 row-span-2 row-start-1 self-start justify-self-end', className)}
{...props} {...props}
/> />
) );
} }
function CardContent({ className, ...props }: React.ComponentProps<"div">) { function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
return <div data-slot="card-content" className={cn("px-8", className)} {...props} /> return <div data-slot="card-content" className={cn('px-8', className)} {...props} />;
} }
function CardFooter({ className, ...props }: React.ComponentProps<"div">) { function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
return ( return (
<div <div
data-slot="card-footer" data-slot="card-footer"
className={cn("flex items-center px-8 [.border-t]:pt-6 [.border-t]:border-border/30", className)} className={cn(
'flex items-center px-8 [.border-t]:pt-6 [.border-t]:border-border/30',
className,
)}
{...props} {...props}
/> />
) );
} }
export { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent } export { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent };

View File

@@ -1,8 +1,8 @@
"use client" 'use client';
import * as React from "react" import * as React from 'react';
import * as LabelPrimitive from "@radix-ui/react-label" import * as LabelPrimitive from '@radix-ui/react-label';
import { Slot } from "@radix-ui/react-slot" import { Slot } from '@radix-ui/react-slot';
import { import {
Controller, Controller,
FormProvider, FormProvider,
@@ -11,23 +11,21 @@ import {
type ControllerProps, type ControllerProps,
type FieldPath, type FieldPath,
type FieldValues, type FieldValues,
} from "react-hook-form" } from 'react-hook-form';
import { cn } from "@workspace/ui/lib/utils" import { cn } from '@workspace/ui/lib/utils';
import { Label } from "@workspace/ui/components/label" import { Label } from '@workspace/ui/components/label';
const Form = FormProvider const Form = FormProvider;
type FormFieldContextValue< type FormFieldContextValue<
TFieldValues extends FieldValues = FieldValues, TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
> = { > = {
name: TName name: TName;
} };
const FormFieldContext = React.createContext<FormFieldContextValue>( const FormFieldContext = React.createContext<FormFieldContextValue>({} as FormFieldContextValue);
{} as FormFieldContextValue
)
const FormField = < const FormField = <
TFieldValues extends FieldValues = FieldValues, TFieldValues extends FieldValues = FieldValues,
@@ -39,21 +37,21 @@ const FormField = <
<FormFieldContext.Provider value={{ name: props.name }}> <FormFieldContext.Provider value={{ name: props.name }}>
<Controller {...props} /> <Controller {...props} />
</FormFieldContext.Provider> </FormFieldContext.Provider>
) );
} };
const useFormField = () => { const useFormField = () => {
const fieldContext = React.useContext(FormFieldContext) const fieldContext = React.useContext(FormFieldContext);
const itemContext = React.useContext(FormItemContext) const itemContext = React.useContext(FormItemContext);
const { getFieldState } = useFormContext() const { getFieldState } = useFormContext();
const formState = useFormState({ name: fieldContext.name }) const formState = useFormState({ name: fieldContext.name });
const fieldState = getFieldState(fieldContext.name, formState) const fieldState = getFieldState(fieldContext.name, formState);
if (!fieldContext) { if (!fieldContext) {
throw new Error("useFormField should be used within <FormField>") throw new Error('useFormField should be used within <FormField>');
} }
const { id } = itemContext const { id } = itemContext;
return { return {
id, id,
@@ -62,97 +60,84 @@ const useFormField = () => {
formDescriptionId: `${id}-form-item-description`, formDescriptionId: `${id}-form-item-description`,
formMessageId: `${id}-form-item-message`, formMessageId: `${id}-form-item-message`,
...fieldState, ...fieldState,
} };
} };
type FormItemContextValue = { type FormItemContextValue = {
id: string id: string;
} };
const FormItemContext = React.createContext<FormItemContextValue>( const FormItemContext = React.createContext<FormItemContextValue>({} as FormItemContextValue);
{} as FormItemContextValue
)
function FormItem({ className, ...props }: React.ComponentProps<"div">) { function FormItem({ className, ...props }: React.ComponentProps<'div'>) {
const id = React.useId() const id = React.useId();
return ( return (
<FormItemContext.Provider value={{ id }}> <FormItemContext.Provider value={{ id }}>
<div <div data-slot="form-item" className={cn('grid gap-2', className)} {...props} />
data-slot="form-item"
className={cn("grid gap-2", className)}
{...props}
/>
</FormItemContext.Provider> </FormItemContext.Provider>
) );
} }
function FormLabel({ function FormLabel({ className, ...props }: React.ComponentProps<typeof LabelPrimitive.Root>) {
className, const { error, formItemId } = useFormField();
...props
}: React.ComponentProps<typeof LabelPrimitive.Root>) {
const { error, formItemId } = useFormField()
return ( return (
<Label <Label
data-slot="form-label" data-slot="form-label"
data-error={!!error} data-error={!!error}
className={cn("data-[error=true]:text-destructive", className)} className={cn('data-[error=true]:text-destructive', className)}
htmlFor={formItemId} htmlFor={formItemId}
{...props} {...props}
/> />
) );
} }
function FormControl({ ...props }: React.ComponentProps<typeof Slot>) { function FormControl({ ...props }: React.ComponentProps<typeof Slot>) {
const { error, formItemId, formDescriptionId, formMessageId } = useFormField() const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
return ( return (
<Slot <Slot
data-slot="form-control" data-slot="form-control"
id={formItemId} id={formItemId}
aria-describedby={ aria-describedby={!error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`}
!error
? `${formDescriptionId}`
: `${formDescriptionId} ${formMessageId}`
}
aria-invalid={!!error} aria-invalid={!!error}
{...props} {...props}
/> />
) );
} }
function FormDescription({ className, ...props }: React.ComponentProps<"p">) { function FormDescription({ className, ...props }: React.ComponentProps<'p'>) {
const { formDescriptionId } = useFormField() const { formDescriptionId } = useFormField();
return ( return (
<p <p
data-slot="form-description" data-slot="form-description"
id={formDescriptionId} id={formDescriptionId}
className={cn("text-muted-foreground text-sm", className)} className={cn('text-muted-foreground text-sm', className)}
{...props} {...props}
/> />
) );
} }
function FormMessage({ className, ...props }: React.ComponentProps<"p">) { function FormMessage({ className, ...props }: React.ComponentProps<'p'>) {
const { error, formMessageId } = useFormField() const { error, formMessageId } = useFormField();
const body = error ? String(error?.message ?? "") : props.children const body = error ? String(error?.message ?? '') : props.children;
if (!body) { if (!body) {
return null return null;
} }
return ( return (
<p <p
data-slot="form-message" data-slot="form-message"
id={formMessageId} id={formMessageId}
className={cn("text-destructive text-sm", className)} className={cn('text-destructive text-sm', className)}
{...props} {...props}
> >
{body} {body}
</p> </p>
) );
} }
export { export {
@@ -164,4 +149,4 @@ export {
FormDescription, FormDescription,
FormMessage, FormMessage,
FormField, FormField,
} };

View File

@@ -1,22 +1,22 @@
import type * as React from "react" import type * as React from 'react';
import { cn } from "@workspace/ui/lib/utils" import { cn } from '@workspace/ui/lib/utils';
function Input({ className, type, ...props }: React.ComponentProps<"input">) { function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
return ( return (
<input <input
type={type} type={type}
data-slot="input" data-slot="input"
className={cn( className={cn(
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-12 w-full min-w-0 rounded-md border-2 bg-transparent px-4 py-3 text-base shadow-md shadow-black/5 transition-all duration-200 outline-none file:inline-flex file:h-8 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm backdrop-blur-sm", 'file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-12 w-full min-w-0 rounded-md border-2 bg-transparent px-4 py-3 text-base shadow-md shadow-black/5 transition-all duration-200 outline-none file:inline-flex file:h-8 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm backdrop-blur-sm',
"focus-visible:border-primary focus-visible:ring-primary/20 focus-visible:ring-4 focus-visible:shadow-lg focus-visible:shadow-primary/10", 'focus-visible:border-primary focus-visible:ring-primary/20 focus-visible:ring-4 focus-visible:shadow-lg focus-visible:shadow-primary/10',
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", 'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
"hover:border-border/80 hover:shadow-lg", 'hover:border-border/80 hover:shadow-lg',
className, className,
)} )}
{...props} {...props}
/> />
) );
} }
export { Input } export { Input };

View File

@@ -1,24 +1,21 @@
"use client" 'use client';
import * as React from "react" import * as React from 'react';
import * as LabelPrimitive from "@radix-ui/react-label" import * as LabelPrimitive from '@radix-ui/react-label';
import { cn } from "@workspace/ui/lib/utils" import { cn } from '@workspace/ui/lib/utils';
function Label({ function Label({ className, ...props }: React.ComponentProps<typeof LabelPrimitive.Root>) {
className,
...props
}: React.ComponentProps<typeof LabelPrimitive.Root>) {
return ( return (
<LabelPrimitive.Root <LabelPrimitive.Root
data-slot="label" data-slot="label"
className={cn( className={cn(
"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50", 'flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50',
className className,
)} )}
{...props} {...props}
/> />
) );
} }
export { Label } export { Label };

View File

@@ -1,16 +1,20 @@
"use client" 'use client';
import type * as React from "react" import type * as React from 'react';
import * as ProgressPrimitive from "@radix-ui/react-progress" import * as ProgressPrimitive from '@radix-ui/react-progress';
import { cn } from "@workspace/ui/lib/utils" import { cn } from '@workspace/ui/lib/utils';
function Progress({ className, value, ...props }: React.ComponentProps<typeof ProgressPrimitive.Root>) { function Progress({
className,
value,
...props
}: React.ComponentProps<typeof ProgressPrimitive.Root>) {
return ( return (
<ProgressPrimitive.Root <ProgressPrimitive.Root
data-slot="progress" data-slot="progress"
className={cn( className={cn(
"bg-primary/20 relative h-3 w-full overflow-hidden rounded-full shadow-inner backdrop-blur-sm border border-primary/10", 'bg-primary/20 relative h-3 w-full overflow-hidden rounded-full shadow-inner backdrop-blur-sm border border-primary/10',
className, className,
)} )}
{...props} {...props}
@@ -21,7 +25,7 @@ function Progress({ className, value, ...props }: React.ComponentProps<typeof Pr
style={{ transform: `translateX(-${100 - (value || 0)}%)` }} style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
/> />
</ProgressPrimitive.Root> </ProgressPrimitive.Root>
) );
} }
export { Progress } export { Progress };

View File

@@ -1,30 +1,30 @@
"use client" 'use client';
import type * as React from "react" import type * as React from 'react';
import * as SelectPrimitive from "@radix-ui/react-select" import * as SelectPrimitive from '@radix-ui/react-select';
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react" import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from 'lucide-react';
import { cn } from "@workspace/ui/lib/utils" import { cn } from '@workspace/ui/lib/utils';
function Select({ ...props }: React.ComponentProps<typeof SelectPrimitive.Root>) { function Select({ ...props }: React.ComponentProps<typeof SelectPrimitive.Root>) {
return <SelectPrimitive.Root data-slot="select" {...props} /> return <SelectPrimitive.Root data-slot="select" {...props} />;
} }
function SelectGroup({ ...props }: React.ComponentProps<typeof SelectPrimitive.Group>) { function SelectGroup({ ...props }: React.ComponentProps<typeof SelectPrimitive.Group>) {
return <SelectPrimitive.Group data-slot="select-group" {...props} /> return <SelectPrimitive.Group data-slot="select-group" {...props} />;
} }
function SelectValue({ ...props }: React.ComponentProps<typeof SelectPrimitive.Value>) { function SelectValue({ ...props }: React.ComponentProps<typeof SelectPrimitive.Value>) {
return <SelectPrimitive.Value data-slot="select-value" {...props} /> return <SelectPrimitive.Value data-slot="select-value" {...props} />;
} }
function SelectTrigger({ function SelectTrigger({
className, className,
size = "default", size = 'default',
children, children,
...props ...props
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & { }: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
size?: "sm" | "default" size?: 'sm' | 'default';
}) { }) {
return ( return (
<SelectPrimitive.Trigger <SelectPrimitive.Trigger
@@ -41,13 +41,13 @@ function SelectTrigger({
<ChevronDownIcon className="size-4 opacity-60 transition-transform duration-200 data-[state=open]:rotate-180" /> <ChevronDownIcon className="size-4 opacity-60 transition-transform duration-200 data-[state=open]:rotate-180" />
</SelectPrimitive.Icon> </SelectPrimitive.Icon>
</SelectPrimitive.Trigger> </SelectPrimitive.Trigger>
) );
} }
function SelectContent({ function SelectContent({
className, className,
children, children,
position = "popper", position = 'popper',
...props ...props
}: React.ComponentProps<typeof SelectPrimitive.Content>) { }: React.ComponentProps<typeof SelectPrimitive.Content>) {
return ( return (
@@ -55,9 +55,9 @@ function SelectContent({
<SelectPrimitive.Content <SelectPrimitive.Content
data-slot="select-content" data-slot="select-content"
className={cn( className={cn(
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-xl border-2 border-border/50 shadow-xl shadow-black/10 backdrop-blur-md", 'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-xl border-2 border-border/50 shadow-xl shadow-black/10 backdrop-blur-md',
position === "popper" && position === 'popper' &&
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1", 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
className, className,
)} )}
position={position} position={position}
@@ -66,9 +66,9 @@ function SelectContent({
<SelectScrollUpButton /> <SelectScrollUpButton />
<SelectPrimitive.Viewport <SelectPrimitive.Viewport
className={cn( className={cn(
"p-2", 'p-2',
position === "popper" && position === 'popper' &&
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1", 'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1',
)} )}
> >
{children} {children}
@@ -76,20 +76,27 @@ function SelectContent({
<SelectScrollDownButton /> <SelectScrollDownButton />
</SelectPrimitive.Content> </SelectPrimitive.Content>
</SelectPrimitive.Portal> </SelectPrimitive.Portal>
) );
} }
function SelectLabel({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.Label>) { function SelectLabel({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.Label>) {
return ( return (
<SelectPrimitive.Label <SelectPrimitive.Label
data-slot="select-label" data-slot="select-label"
className={cn("text-muted-foreground px-3 py-2 text-xs font-semibold uppercase tracking-wider", className)} className={cn(
'text-muted-foreground px-3 py-2 text-xs font-semibold uppercase tracking-wider',
className,
)}
{...props} {...props}
/> />
) );
} }
function SelectItem({ className, children, ...props }: React.ComponentProps<typeof SelectPrimitive.Item>) { function SelectItem({
className,
children,
...props
}: React.ComponentProps<typeof SelectPrimitive.Item>) {
return ( return (
<SelectPrimitive.Item <SelectPrimitive.Item
data-slot="select-item" data-slot="select-item"
@@ -106,29 +113,35 @@ function SelectItem({ className, children, ...props }: React.ComponentProps<type
</span> </span>
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText> <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item> </SelectPrimitive.Item>
) );
} }
function SelectSeparator({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.Separator>) { function SelectSeparator({
className,
...props
}: React.ComponentProps<typeof SelectPrimitive.Separator>) {
return ( return (
<SelectPrimitive.Separator <SelectPrimitive.Separator
data-slot="select-separator" data-slot="select-separator"
className={cn("bg-border pointer-events-none -mx-1 my-2 h-px", className)} className={cn('bg-border pointer-events-none -mx-1 my-2 h-px', className)}
{...props} {...props}
/> />
) );
} }
function SelectScrollUpButton({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) { function SelectScrollUpButton({
className,
...props
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
return ( return (
<SelectPrimitive.ScrollUpButton <SelectPrimitive.ScrollUpButton
data-slot="select-scroll-up-button" data-slot="select-scroll-up-button"
className={cn("flex cursor-default items-center justify-center py-1", className)} className={cn('flex cursor-default items-center justify-center py-1', className)}
{...props} {...props}
> >
<ChevronUpIcon className="size-4" /> <ChevronUpIcon className="size-4" />
</SelectPrimitive.ScrollUpButton> </SelectPrimitive.ScrollUpButton>
) );
} }
function SelectScrollDownButton({ function SelectScrollDownButton({
@@ -138,12 +151,12 @@ function SelectScrollDownButton({
return ( return (
<SelectPrimitive.ScrollDownButton <SelectPrimitive.ScrollDownButton
data-slot="select-scroll-down-button" data-slot="select-scroll-down-button"
className={cn("flex cursor-default items-center justify-center py-1", className)} className={cn('flex cursor-default items-center justify-center py-1', className)}
{...props} {...props}
> >
<ChevronDownIcon className="size-4" /> <ChevronDownIcon className="size-4" />
</SelectPrimitive.ScrollDownButton> </SelectPrimitive.ScrollDownButton>
) );
} }
export { export {
@@ -157,4 +170,4 @@ export {
SelectSeparator, SelectSeparator,
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} };

View File

@@ -1,13 +1,13 @@
"use client" 'use client';
import type * as React from "react" import type * as React from 'react';
import * as SeparatorPrimitive from "@radix-ui/react-separator" import * as SeparatorPrimitive from '@radix-ui/react-separator';
import { cn } from "@workspace/ui/lib/utils" import { cn } from '@workspace/ui/lib/utils';
function Separator({ function Separator({
className, className,
orientation = "horizontal", orientation = 'horizontal',
decorative = true, decorative = true,
...props ...props
}: React.ComponentProps<typeof SeparatorPrimitive.Root>) { }: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
@@ -17,12 +17,12 @@ function Separator({
decorative={decorative} decorative={decorative}
orientation={orientation} orientation={orientation}
className={cn( className={cn(
"bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px data-[orientation=vertical]:bg-gradient-to-b", 'bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px data-[orientation=vertical]:bg-gradient-to-b',
className, className,
)} )}
{...props} {...props}
/> />
) );
} }
export { Separator } export { Separator };

View File

@@ -1,18 +1,18 @@
import type * as React from "react" import type * as React from 'react';
import { cn } from "@workspace/ui/lib/utils" import { cn } from '@workspace/ui/lib/utils';
function Textarea({ className, ...props }: React.ComponentProps<"textarea">) { function Textarea({ className, ...props }: React.ComponentProps<'textarea'>) {
return ( return (
<textarea <textarea
data-slot="textarea" data-slot="textarea"
className={cn( className={cn(
"border-input placeholder:text-muted-foreground focus-visible:border-primary focus-visible:ring-primary/20 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-20 w-full rounded-md border-2 bg-transparent px-4 py-3 text-base shadow-md shadow-black/5 transition-all duration-200 outline-none focus-visible:ring-4 focus-visible:shadow-lg focus-visible:shadow-primary/10 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm backdrop-blur-sm hover:border-border/80 hover:shadow-lg resize-none", 'border-input placeholder:text-muted-foreground focus-visible:border-primary focus-visible:ring-primary/20 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-20 w-full rounded-md border-2 bg-transparent px-4 py-3 text-base shadow-md shadow-black/5 transition-all duration-200 outline-none focus-visible:ring-4 focus-visible:shadow-lg focus-visible:shadow-primary/10 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm backdrop-blur-sm hover:border-border/80 hover:shadow-lg resize-none',
className, className,
)} )}
{...props} {...props}
/> />
) );
} }
export { Textarea } export { Textarea };

View File

@@ -1,6 +1,6 @@
import { clsx, type ClassValue } from "clsx" import { clsx, type ClassValue } from 'clsx';
import { twMerge } from "tailwind-merge" import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) { export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs)) return twMerge(clsx(inputs));
} }

View File

@@ -1,13 +1,13 @@
@import "tailwindcss"; @import 'tailwindcss';
@source "../../../apps/**/*.{ts,tsx}"; @source "../../../apps/**/*.{ts,tsx}";
@source "../../../components/**/*.{ts,tsx}"; @source "../../../components/**/*.{ts,tsx}";
@source "../**/*.{ts,tsx}"; @source "../**/*.{ts,tsx}";
@import "tw-animate-css"; @import 'tw-animate-css';
@theme { @theme {
--font-sans: "var(--font-sans)"; --font-sans: 'var(--font-sans)';
--font-marcellus: "var(--font-marcellus)"; --font-marcellus: 'var(--font-marcellus)';
} }
@custom-variant dark (&:is(.dark *)); @custom-variant dark (&:is(.dark *));

4293
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,3 @@
packages: packages:
- "apps/*" - 'apps/*'
- "packages/*" - 'packages/*'

View File

@@ -1,4 +1,3 @@
{ {
"extends": "@workspace/typescript-config/base.json" "extends": "@workspace/typescript-config/base.json"
} }