prettier setup
This commit is contained in:
@@ -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
11
.prettierignore
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
node_modules/
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
.next/
|
||||||
|
out/
|
||||||
|
coverage/
|
||||||
|
.DS_Store
|
||||||
|
pnpm-lock.yaml
|
||||||
|
*.env
|
||||||
|
*.log
|
||||||
|
.turbo/
|
||||||
8
.prettierrc
Normal file
8
.prettierrc
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "all",
|
||||||
|
"printWidth": 100,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"endOfLine": "lf"
|
||||||
|
}
|
||||||
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@@ -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"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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';
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
import { handlers } from "@workspace/auth";
|
import { handlers } from '@workspace/auth';
|
||||||
export const { GET, POST } = handlers;
|
export const { GET, POST } = handlers;
|
||||||
|
|||||||
@@ -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>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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).*)'],
|
||||||
}
|
};
|
||||||
|
|||||||
12
apps/admin/next-auth.d.ts
vendored
12
apps/admin/next-auth.d.ts
vendored
@@ -1,19 +1,19 @@
|
|||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export { default } from "@workspace/ui/postcss.config";
|
export { default } from '@workspace/ui/postcss.config';
|
||||||
|
|||||||
@@ -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"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
import { handlers } from "@workspace/auth";
|
import { handlers } from '@workspace/auth';
|
||||||
export const { GET, POST } = handlers;
|
export const { GET, POST } = handlers;
|
||||||
|
|||||||
@@ -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>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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).*)'],
|
||||||
}
|
};
|
||||||
|
|||||||
12
apps/student/next-auth.d.ts
vendored
12
apps/student/next-auth.d.ts
vendored
@@ -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,10 +11,10 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export { default } from "@workspace/ui/postcss.config";
|
export { default } from '@workspace/ui/postcss.config';
|
||||||
|
|||||||
@@ -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"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
14
packages/auth/types.d.ts
vendored
14
packages/auth/types.d.ts
vendored
@@ -1,20 +1,20 @@
|
|||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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!,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
@@ -843,4 +807,4 @@
|
|||||||
"schemas": {},
|
"schemas": {},
|
||||||
"tables": {}
|
"tables": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
@@ -843,4 +807,4 @@
|
|||||||
"schemas": {},
|
"schemas": {},
|
||||||
"tables": {}
|
"tables": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
@@ -890,4 +852,4 @@
|
|||||||
"schemas": {},
|
"schemas": {},
|
||||||
"tables": {}
|
"tables": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
@@ -897,4 +856,4 @@
|
|||||||
"schemas": {},
|
"schemas": {},
|
||||||
"tables": {}
|
"tables": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
@@ -748,4 +715,4 @@
|
|||||||
"schemas": {},
|
"schemas": {},
|
||||||
"tables": {}
|
"tables": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
@@ -766,4 +733,4 @@
|
|||||||
"schemas": {},
|
"schemas": {},
|
||||||
"tables": {}
|
"tables": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,4 +45,4 @@
|
|||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
|||||||
@@ -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/**'],
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
|
|||||||
@@ -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',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
|
|||||||
24
packages/eslint-config/react-internal.js
vendored
24
packages/eslint-config/react-internal.js
vendored
@@ -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',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 };
|
||||||
|
|||||||
@@ -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 };
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -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 };
|
||||||
|
|||||||
@@ -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 };
|
||||||
|
|||||||
@@ -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 };
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -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 };
|
||||||
|
|||||||
@@ -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 };
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
4293
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,3 @@
|
|||||||
packages:
|
packages:
|
||||||
- "apps/*"
|
- 'apps/*'
|
||||||
- "packages/*"
|
- 'packages/*'
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
{
|
{
|
||||||
"extends": "@workspace/typescript-config/base.json"
|
"extends": "@workspace/typescript-config/base.json"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user