Sfoglia il codice sorgente

feat: header login

Carson 11 mesi fa
parent
commit
60952183bb

+ 78 - 0
app/api/auth/[...nextauth]/route.ts

@@ -0,0 +1,78 @@
+import NextAuth from "next-auth";
+import CredentialsProvider from "next-auth/providers/credentials";
+import * as R from "ramda";
+
+export const authOptions = {
+  // Configure one or more authentication providers
+  providers: [
+    CredentialsProvider({
+      // The name to display on the sign in form (e.g. 'Sign in with...')
+      name: "Cocorobo cloud",
+      // The credentials is used to generate a suitable form on the sign in page.
+      // You can specify whatever fields you are expecting to be submitted.
+      // e.g. domain, username, password, 2FA token, etc.
+      // You can pass any HTML attribute to the <input> tag through the object.
+      credentials: {
+        loginUsername: { label: "用户名", type: "text" },
+        loginPassword: { label: "密码", type: "password" },
+      },
+      async authorize(credentials, req) {
+        // You need to provide your own logic here that takes the credentials
+        // submitted and returns either a object representing a user or value
+        // that is false/null if the credentials are invalid.
+        // e.g. return { id: 1, name: 'J Smith', email: 'jsmith@example.com' }
+        // You can also use the `req` object to obtain additional parameters
+        // (i.e., the request IP address)
+        const res = await fetch("https://beta.api.cocorobo.cn/api/user", {
+          method: "POST",
+          body: JSON.stringify(
+            R.pick(["loginUsername", "loginPassword"], credentials)
+          ),
+          headers: {
+            "Content-Type": "application/json",
+            Origin: "https://edu.cocorobo.cn",
+          },
+        });
+        if (res.status !== 200) {
+          return null;
+        }
+        const resJson = await res.json();
+        const user = resJson?.[0]?.[0];
+
+        // If no error and we have user data, return it
+        if (res.ok && user && user.active) {
+          return { ...user, id: user.userid, name: user.username };
+        }
+        // Return null if user data could not be retrieved
+        return null;
+      },
+    }),
+  ],
+  callbacks: {
+    async session({ session, token }) {
+      console.log(session, token);
+      // Send properties to the client, like an access_token from a provider.
+      session.user.id = token.sub;
+      try {
+        const res = await fetch(
+          `https://pbl.cocorobo.cn/api/pbl/selectUser?userid=${token.sub}`,
+          {
+            method: "GET",
+            headers: {
+              "Content-Type": "application/json",
+            },
+          }
+        );
+        const username = (await res.json())?.[0]?.[0]?.username;
+        session.user.name = username;
+      } catch (e) {
+        session.user.name = token.name;
+      }
+      return session;
+    },
+  },
+};
+
+const handler = NextAuth(authOptions);
+
+export { handler as GET, handler as POST };

+ 2 - 2
app/globals.css

@@ -2,7 +2,7 @@
 @tailwind components;
 @tailwind utilities;
 
-:root {
+/* :root {
   --foreground-rgb: 0, 0, 0;
   --background-start-rgb: 214, 219, 220;
   --background-end-rgb: 255, 255, 255;
@@ -30,4 +30,4 @@ body {
   .text-balance {
     text-wrap: balance;
   }
-}
+} */

+ 12 - 6
app/layout.tsx

@@ -2,12 +2,14 @@ import type { Metadata } from "next";
 import { Inter } from "next/font/google";
 import "./globals.css";
 import { TrpcContextProvider } from "@/components/providers/TrpcContextProvider";
+import { SessionProvider } from "@/components/providers/SessionProvider";
+
 
 const inter = Inter({ subsets: ["latin"] });
 
 export const metadata: Metadata = {
-  title: "Create Next App",
-  description: "Generated by create next app",
+  title: "Coco Apps",
+  description: "Cocorobo's Apps Platform",
 };
 
 export default function RootLayout({
@@ -15,12 +17,16 @@ export default function RootLayout({
 }: Readonly<{
   children: React.ReactNode;
 }>) {
+  // const [theme] = useState("cupcake")
+  const theme = "cupcake"
   return (
-    <html lang="en">
+    <html lang="en" data-theme={theme}>
       <body className={inter.className}>
-        <TrpcContextProvider>
-          {children}
-        </TrpcContextProvider>
+        <SessionProvider>
+          <TrpcContextProvider>
+            {children}
+          </TrpcContextProvider>
+        </SessionProvider>
       </body>
     </html>
   );

+ 7 - 0
app/run-agent-flow/components/ASide.tsx

@@ -0,0 +1,7 @@
+import React from 'react'
+const ASide = () => {
+  return (
+    <div className="  shadow-xl rounded-box min-w-[350px] p-2">aside</div>
+  )
+}
+export default React.memo(ASide)

+ 8 - 0
app/run-agent-flow/components/Flow.tsx

@@ -0,0 +1,8 @@
+'use client';
+import React from 'react'
+const Flow = () => {
+  return (
+    <div className="shadow-xl rounded-box min-h-[150px] p-2">flow</div>
+  )
+}
+export default React.memo(React.forwardRef(Flow))

+ 89 - 0
app/run-agent-flow/components/Header.tsx

@@ -0,0 +1,89 @@
+'use client'
+import { BsCaretDownFill } from "react-icons/bs";
+import { useSession, signIn, signOut } from "next-auth/react"
+import { createRef, useEffect, useState } from "react";
+import { useQuery } from "@tanstack/react-query";
+import { trpc } from "@/lib/trpc";
+
+export default function Header() {
+  const { data: session, status } = useSession()
+
+  const [org, setOrg] = useState('')
+  const [username, setUsername] = useState('')
+  const [password, setPassword] = useState('')
+  const [isLogInFail, setIsLogInFail] = useState(false)
+
+  const orgQuery = trpc.org.bySlug.useQuery({ mode: org })
+
+  const logOut = async () => {
+    await signOut({ redirect: false })
+  }
+  const logIn = async () => {
+    const loginUsername = orgQuery.data?.mail ? `${username}@${orgQuery.data?.mail}` : `${username}@cocorobo.cc`
+    const loginPassword = btoa(password)
+    // const res = await signIn('credentials', { redirect: false, loginUsername: 'lanlinling@szjky.com', loginPassword: 'MTIzNDU2' })
+    const res = await signIn('credentials', { redirect: false, loginUsername, loginPassword })
+    console.log(res)
+    if (!res.ok) {
+      setIsLogInFail(true)
+    }
+  }
+  useEffect(() => {
+    setIsLogInFail(false)
+  }, [username, password, org])
+
+  return (
+    <div className="navbar bg-base-100 shadow-xl rounded-box justify-center min-h-4 relative">
+      <div className="dropdown">
+        <div tabIndex={0} role="button" className="btn btn-sm btn-wide btn-ghost">选择对话<BsCaretDownFill /></div>
+        <ul tabIndex={0} className="dropdown-content menu bg-base-100 rounded-box z-[1] w-52 p-2 shadow">
+          <li><a>Item 1</a></li>
+          <li><a>Item 2</a></li>
+        </ul>
+      </div>
+      {status === 'authenticated'
+        ? (
+          <div className="absolute right-4 flex gap-2">
+            <div>
+              <p>Hi, {session.user?.name}</p>
+            </div>
+            <button className='btn btn-sm' onClick={logOut}>退出登录</button>
+          </div>
+        ) : (
+          <>
+            <dialog className="modal modal-open" onCancel={event => event.preventDefault()}>
+              <div className="modal-box">
+                <h3 className="font-bold text-lg">您需要先登录</h3>
+                <div className="w-full flex flex-col items-center gap-2 py-2">
+                  {isLogInFail && <div role="alert" className="alert alert-error">
+                    <span>账号或密码错误</span>
+                  </div>}
+                  <label className="form-control w-full max-w-xs">
+                    <div className="label">
+                      <span className="label-text">组织(选填)</span>
+                      {orgQuery?.data?.name && <span className="label-text-alt text-indigo-400">{orgQuery.data.name}</span>}
+                    </div>
+                    <input type="text" placeholder="" className="input input-bordered w-full max-w-xs" onChange={e => setOrg(e.target.value)} />
+                  </label>
+                  <label className="form-control w-full max-w-xs">
+                    <div className="label">
+                      <span className="label-text">用户名</span>
+                    </div>
+                    <input type="text" placeholder="" className="input input-bordered w-full max-w-xs" onChange={e => setUsername(e.target.value)} />
+                  </label>
+                  <label className="form-control w-full max-w-xs">
+                    <div className="label">
+                      <span className="label-text">密码</span>
+                    </div>
+                    <input type="password" placeholder="" className="input input-bordered w-full max-w-xs" onChange={e => setPassword(e.target.value)} />
+                  </label>
+                  <button className='btn btn-wide' disabled={!username || !password} onClick={logIn}>登录</button>
+                </div>
+              </div>
+            </dialog>
+          </>
+        )
+      }
+    </div>
+  )
+}

+ 37 - 0
app/run-agent-flow/components/NodeRender.tsx

@@ -0,0 +1,37 @@
+'use client';
+
+import React, { useMemo } from 'react'
+import { BsArrowLeft, BsArrowRight } from "react-icons/bs";
+import Form from './NodeType/Form';
+import * as R from 'ramda'
+
+const NodeRender = ({ node }) => {
+  const Comp = useMemo(() => {
+    return R.cond([
+      [R.propEq('form_card', 'type'), R.always(Form)],
+      [R.T, R.always('div')],
+    ])(node)
+  }, [node?.id])
+  return (
+    // <div className="flex-1 shadow-xl rounded-box p-2">node render</div>
+    <div className="card card-compact shadow-xl flex-1">
+      <div className="card-body">
+        <div className="card-title rounded-box bg-slate-200 p-2">
+          <h2 className="flex-1">
+            Card title!
+          </h2>
+          <button className='btn btn-circle btn-sm'><BsArrowLeft /></button>
+          <button className='btn btn-circle btn-sm'><BsArrowRight /></button>
+        </div>
+        <Comp node={node}></Comp>
+        {/* TODO */}
+
+        {/* <div className="card-actions justify-end">
+          <button className="btn btn-primary">确认,下一步</button>
+        </div> */}
+      </div>
+    </div>
+  )
+}
+
+export default React.memo(React.forwardRef(NodeRender))

+ 7 - 0
app/run-agent-flow/components/NodeType/Form.tsx

@@ -0,0 +1,7 @@
+import React from 'react'
+const Form = ({node}) => {
+  return (
+    <div className="">form card {JSON.stringify(node)}</div>
+  )
+}
+export default React.memo(Form)

+ 35 - 0
app/run-agent-flow/page.tsx

@@ -0,0 +1,35 @@
+'use client';
+
+import React from "react";
+import ASide from "./components/ASide";
+import Flow from "./components/Flow";
+import Header from "./components/Header";
+import NodeRender from "./components/NodeRender";
+import { trpc } from "@/lib/trpc";
+import { useQuery } from '@tanstack/react-query'
+import { useSearchParam } from 'react-use';
+import { useSession, signIn, signOut } from "next-auth/react"
+
+
+const RunAgentFlow = () => {
+  const { data: session, status } = useSession()
+  // const multiAgentId = useSearchParam('multiAgentId')
+  // const dialogsQuery = useQuery({queryKey: ['dialogs', multiAgentId], queryFn: () => {
+  //   fetch({})
+  // }})
+  
+  return (
+    <main className="flex min-h-screen flex-col items-center justify-between p-2 gap-2">
+      <Header></Header>
+      <div className="flex align-stretch flex-1 w-full gap-2">
+        <div className="flex-1 flex flex-col align-stretch gap-2">
+          <Flow></Flow>
+          <NodeRender></NodeRender>
+        </div>
+        <ASide></ASide>
+      </div>
+    </main>
+  )
+}
+
+export default React.memo(React.forwardRef(RunAgentFlow))

+ 11 - 0
components/providers/SessionProvider.tsx

@@ -0,0 +1,11 @@
+'use client'
+import { useSession, signIn, signOut, SessionProvider as _SessionProvider } from "next-auth/react"
+import { type ReactNode } from "react"
+
+export function SessionProvider({ children }: { children: ReactNode }) {
+  return (
+    <_SessionProvider>
+      {children}
+    </_SessionProvider>
+  )
+}

+ 1 - 1
components/providers/TrpcContextProvider.tsx

@@ -3,7 +3,7 @@
 import { useState, type ReactNode } from "react";
 import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
 import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
-import { trpc } from "@/utils/trpc";
+import { trpc } from "@/lib/trpc";
 import { httpBatchLink } from "@trpc/client";
 
 export function TrpcContextProvider({ children }: { children: ReactNode }) {

+ 0 - 0
utils/trpc.ts → lib/trpc.ts


+ 391 - 6
package-lock.json

@@ -14,11 +14,13 @@
         "@trpc/server": "^11.0.0-rc.482",
         "jotai": "^2.9.3",
         "next": "14.2.5",
+        "next-auth": "^4.24.7",
         "ramda": "^0.30.1",
         "react": "^18",
         "react-dom": "^18",
         "react-hook-form": "^7.52.2",
         "react-icons": "^5.3.0",
+        "react-use": "^17.5.1",
         "tailwind-merge": "^2.5.2",
         "zod": "^3.23.8"
       },
@@ -48,6 +50,17 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/@babel/runtime": {
+      "version": "7.25.0",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz",
+      "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==",
+      "dependencies": {
+        "regenerator-runtime": "^0.14.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
     "node_modules/@eslint-community/eslint-utils": {
       "version": "4.4.0",
       "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
@@ -218,8 +231,7 @@
     "node_modules/@jridgewell/sourcemap-codec": {
       "version": "1.5.0",
       "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
-      "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
-      "dev": true
+      "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="
     },
     "node_modules/@jridgewell/trace-mapping": {
       "version": "0.3.25",
@@ -415,6 +427,14 @@
         "node": ">= 8"
       }
     },
+    "node_modules/@panva/hkdf": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.2.1.tgz",
+      "integrity": "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==",
+      "funding": {
+        "url": "https://github.com/sponsors/panva"
+      }
+    },
     "node_modules/@pkgjs/parseargs": {
       "version": "0.11.0",
       "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
@@ -530,6 +550,11 @@
         "https://trpc.io/sponsor"
       ]
     },
+    "node_modules/@types/js-cookie": {
+      "version": "2.2.7",
+      "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-2.2.7.tgz",
+      "integrity": "sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA=="
+    },
     "node_modules/@types/json5": {
       "version": "0.0.29",
       "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
@@ -712,6 +737,11 @@
       "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
       "dev": true
     },
+    "node_modules/@xobotyi/scrollbar-width": {
+      "version": "1.9.5",
+      "resolved": "https://registry.npmjs.org/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz",
+      "integrity": "sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ=="
+    },
     "node_modules/acorn": {
       "version": "8.12.1",
       "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
@@ -1208,6 +1238,22 @@
       "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
       "dev": true
     },
+    "node_modules/cookie": {
+      "version": "0.5.0",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+      "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/copy-to-clipboard": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz",
+      "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==",
+      "dependencies": {
+        "toggle-selection": "^1.0.6"
+      }
+    },
     "node_modules/cross-spawn": {
       "version": "7.0.3",
       "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -1222,6 +1268,14 @@
         "node": ">= 8"
       }
     },
+    "node_modules/css-in-js-utils": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz",
+      "integrity": "sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==",
+      "dependencies": {
+        "hyphenate-style-name": "^1.0.3"
+      }
+    },
     "node_modules/css-selector-tokenizer": {
       "version": "0.8.0",
       "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz",
@@ -1232,6 +1286,18 @@
         "fastparse": "^1.1.2"
       }
     },
+    "node_modules/css-tree": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
+      "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
+      "dependencies": {
+        "mdn-data": "2.0.14",
+        "source-map": "^0.6.1"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
     "node_modules/cssesc": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
@@ -1247,8 +1313,7 @@
     "node_modules/csstype": {
       "version": "3.1.3",
       "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
-      "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
-      "devOptional": true
+      "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
     },
     "node_modules/culori": {
       "version": "3.3.0",
@@ -1485,6 +1550,14 @@
         "node": ">=10.13.0"
       }
     },
+    "node_modules/error-stack-parser": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz",
+      "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==",
+      "dependencies": {
+        "stackframe": "^1.3.4"
+      }
+    },
     "node_modules/es-abstract": {
       "version": "1.23.3",
       "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz",
@@ -2090,8 +2163,7 @@
     "node_modules/fast-deep-equal": {
       "version": "3.1.3",
       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
-      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
-      "dev": true
+      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
     },
     "node_modules/fast-glob": {
       "version": "3.3.2",
@@ -2133,6 +2205,16 @@
       "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
       "dev": true
     },
+    "node_modules/fast-shallow-equal": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fast-shallow-equal/-/fast-shallow-equal-1.0.0.tgz",
+      "integrity": "sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw=="
+    },
+    "node_modules/fastest-stable-stringify": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/fastest-stable-stringify/-/fastest-stable-stringify-2.0.2.tgz",
+      "integrity": "sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q=="
+    },
     "node_modules/fastparse": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
@@ -2550,6 +2632,11 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/hyphenate-style-name": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz",
+      "integrity": "sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw=="
+    },
     "node_modules/ignore": {
       "version": "5.3.2",
       "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@@ -2601,6 +2688,14 @@
       "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
       "dev": true
     },
+    "node_modules/inline-style-prefixer": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-7.0.1.tgz",
+      "integrity": "sha512-lhYo5qNTQp3EvSSp3sRvXMbVQTLrvGV6DycRMJ5dm2BLMiJ30wpXKdDdgX+GmJZ5uQMucwRKHamXSst3Sj/Giw==",
+      "dependencies": {
+        "css-in-js-utils": "^3.1.0"
+      }
+    },
     "node_modules/internal-slot": {
       "version": "1.0.7",
       "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz",
@@ -3053,6 +3148,14 @@
         "jiti": "bin/jiti.js"
       }
     },
+    "node_modules/jose": {
+      "version": "4.15.9",
+      "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz",
+      "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==",
+      "funding": {
+        "url": "https://github.com/sponsors/panva"
+      }
+    },
     "node_modules/jotai": {
       "version": "2.9.3",
       "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.9.3.tgz",
@@ -3073,6 +3176,11 @@
         }
       }
     },
+    "node_modules/js-cookie": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz",
+      "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ=="
+    },
     "node_modules/js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -3228,6 +3336,11 @@
       "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
       "dev": true
     },
+    "node_modules/mdn-data": {
+      "version": "2.0.14",
+      "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
+      "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow=="
+    },
     "node_modules/merge2": {
       "version": "1.4.1",
       "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -3297,6 +3410,25 @@
         "thenify-all": "^1.0.0"
       }
     },
+    "node_modules/nano-css": {
+      "version": "5.6.2",
+      "resolved": "https://registry.npmjs.org/nano-css/-/nano-css-5.6.2.tgz",
+      "integrity": "sha512-+6bHaC8dSDGALM1HJjOHVXpuastdu2xFoZlC77Jh4cg+33Zcgm+Gxd+1xsnpZK14eyHObSp82+ll5y3SX75liw==",
+      "dependencies": {
+        "@jridgewell/sourcemap-codec": "^1.4.15",
+        "css-tree": "^1.1.2",
+        "csstype": "^3.1.2",
+        "fastest-stable-stringify": "^2.0.2",
+        "inline-style-prefixer": "^7.0.1",
+        "rtl-css-js": "^1.16.1",
+        "stacktrace-js": "^2.0.2",
+        "stylis": "^4.3.0"
+      },
+      "peerDependencies": {
+        "react": "*",
+        "react-dom": "*"
+      }
+    },
     "node_modules/nanoid": {
       "version": "3.3.7",
       "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
@@ -3369,6 +3501,33 @@
         }
       }
     },
+    "node_modules/next-auth": {
+      "version": "4.24.7",
+      "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.24.7.tgz",
+      "integrity": "sha512-iChjE8ov/1K/z98gdKbn2Jw+2vLgJtVV39X+rCP5SGnVQuco7QOr19FRNGMIrD8d3LYhHWV9j9sKLzq1aDWWQQ==",
+      "dependencies": {
+        "@babel/runtime": "^7.20.13",
+        "@panva/hkdf": "^1.0.2",
+        "cookie": "^0.5.0",
+        "jose": "^4.15.5",
+        "oauth": "^0.9.15",
+        "openid-client": "^5.4.0",
+        "preact": "^10.6.3",
+        "preact-render-to-string": "^5.1.19",
+        "uuid": "^8.3.2"
+      },
+      "peerDependencies": {
+        "next": "^12.2.5 || ^13 || ^14",
+        "nodemailer": "^6.6.5",
+        "react": "^17.0.2 || ^18",
+        "react-dom": "^17.0.2 || ^18"
+      },
+      "peerDependenciesMeta": {
+        "nodemailer": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/next/node_modules/postcss": {
       "version": "8.4.31",
       "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
@@ -3405,6 +3564,11 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/oauth": {
+      "version": "0.9.15",
+      "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz",
+      "integrity": "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA=="
+    },
     "node_modules/object-assign": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -3541,6 +3705,14 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/oidc-token-hash": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.3.tgz",
+      "integrity": "sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==",
+      "engines": {
+        "node": "^10.13.0 || >=12.0.0"
+      }
+    },
     "node_modules/once": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -3550,6 +3722,39 @@
         "wrappy": "1"
       }
     },
+    "node_modules/openid-client": {
+      "version": "5.6.5",
+      "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.6.5.tgz",
+      "integrity": "sha512-5P4qO9nGJzB5PI0LFlhj4Dzg3m4odt0qsJTfyEtZyOlkgpILwEioOhVVJOrS1iVH494S4Ee5OCjjg6Bf5WOj3w==",
+      "dependencies": {
+        "jose": "^4.15.5",
+        "lru-cache": "^6.0.0",
+        "object-hash": "^2.2.0",
+        "oidc-token-hash": "^5.0.3"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/panva"
+      }
+    },
+    "node_modules/openid-client/node_modules/lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/openid-client/node_modules/object-hash": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz",
+      "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
     "node_modules/optionator": {
       "version": "0.9.4",
       "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@@ -3866,6 +4071,26 @@
       "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
       "dev": true
     },
+    "node_modules/preact": {
+      "version": "10.23.2",
+      "resolved": "https://registry.npmjs.org/preact/-/preact-10.23.2.tgz",
+      "integrity": "sha512-kKYfePf9rzKnxOAKDpsWhg/ysrHPqT+yQ7UW4JjdnqjFIeNUnNcEJvhuA8fDenxAGWzUqtd51DfVg7xp/8T9NA==",
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/preact"
+      }
+    },
+    "node_modules/preact-render-to-string": {
+      "version": "5.2.6",
+      "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.6.tgz",
+      "integrity": "sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==",
+      "dependencies": {
+        "pretty-format": "^3.8.0"
+      },
+      "peerDependencies": {
+        "preact": ">=10"
+      }
+    },
     "node_modules/prelude-ls": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -3875,6 +4100,11 @@
         "node": ">= 0.8.0"
       }
     },
+    "node_modules/pretty-format": {
+      "version": "3.8.0",
+      "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz",
+      "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew=="
+    },
     "node_modules/prop-types": {
       "version": "15.8.1",
       "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@@ -3976,6 +4206,40 @@
       "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
       "dev": true
     },
+    "node_modules/react-universal-interface": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/react-universal-interface/-/react-universal-interface-0.6.2.tgz",
+      "integrity": "sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==",
+      "peerDependencies": {
+        "react": "*",
+        "tslib": "*"
+      }
+    },
+    "node_modules/react-use": {
+      "version": "17.5.1",
+      "resolved": "https://registry.npmjs.org/react-use/-/react-use-17.5.1.tgz",
+      "integrity": "sha512-LG/uPEVRflLWMwi3j/sZqR00nF6JGqTTDblkXK2nzXsIvij06hXl1V/MZIlwj1OKIQUtlh1l9jK8gLsRyCQxMg==",
+      "dependencies": {
+        "@types/js-cookie": "^2.2.6",
+        "@xobotyi/scrollbar-width": "^1.9.5",
+        "copy-to-clipboard": "^3.3.1",
+        "fast-deep-equal": "^3.1.3",
+        "fast-shallow-equal": "^1.0.0",
+        "js-cookie": "^2.2.1",
+        "nano-css": "^5.6.2",
+        "react-universal-interface": "^0.6.2",
+        "resize-observer-polyfill": "^1.5.1",
+        "screenfull": "^5.1.0",
+        "set-harmonic-interval": "^1.0.1",
+        "throttle-debounce": "^3.0.1",
+        "ts-easing": "^0.2.0",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "react": "*",
+        "react-dom": "*"
+      }
+    },
     "node_modules/read-cache": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
@@ -4018,6 +4282,11 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/regenerator-runtime": {
+      "version": "0.14.1",
+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+      "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
+    },
     "node_modules/regexp.prototype.flags": {
       "version": "1.5.2",
       "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz",
@@ -4036,6 +4305,11 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/resize-observer-polyfill": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
+      "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="
+    },
     "node_modules/resolve": {
       "version": "1.22.8",
       "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
@@ -4118,6 +4392,14 @@
         "url": "https://github.com/sponsors/isaacs"
       }
     },
+    "node_modules/rtl-css-js": {
+      "version": "1.16.1",
+      "resolved": "https://registry.npmjs.org/rtl-css-js/-/rtl-css-js-1.16.1.tgz",
+      "integrity": "sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==",
+      "dependencies": {
+        "@babel/runtime": "^7.1.2"
+      }
+    },
     "node_modules/run-parallel": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -4184,6 +4466,17 @@
         "loose-envify": "^1.1.0"
       }
     },
+    "node_modules/screenfull": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/screenfull/-/screenfull-5.2.0.tgz",
+      "integrity": "sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==",
+      "engines": {
+        "node": ">=0.10.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/semver": {
       "version": "7.6.3",
       "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
@@ -4228,6 +4521,14 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/set-harmonic-interval": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/set-harmonic-interval/-/set-harmonic-interval-1.0.1.tgz",
+      "integrity": "sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g==",
+      "engines": {
+        "node": ">=6.9"
+      }
+    },
     "node_modules/shebang-command": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -4288,6 +4589,14 @@
         "node": ">=8"
       }
     },
+    "node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/source-map-js": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
@@ -4296,6 +4605,46 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/stack-generator": {
+      "version": "2.0.10",
+      "resolved": "https://registry.npmjs.org/stack-generator/-/stack-generator-2.0.10.tgz",
+      "integrity": "sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ==",
+      "dependencies": {
+        "stackframe": "^1.3.4"
+      }
+    },
+    "node_modules/stackframe": {
+      "version": "1.3.4",
+      "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz",
+      "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw=="
+    },
+    "node_modules/stacktrace-gps": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/stacktrace-gps/-/stacktrace-gps-3.1.2.tgz",
+      "integrity": "sha512-GcUgbO4Jsqqg6RxfyTHFiPxdPqF+3LFmQhm7MgCuYQOYuWyqxo5pwRPz5d/u6/WYJdEnWfK4r+jGbyD8TSggXQ==",
+      "dependencies": {
+        "source-map": "0.5.6",
+        "stackframe": "^1.3.4"
+      }
+    },
+    "node_modules/stacktrace-gps/node_modules/source-map": {
+      "version": "0.5.6",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz",
+      "integrity": "sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/stacktrace-js": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/stacktrace-js/-/stacktrace-js-2.0.2.tgz",
+      "integrity": "sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg==",
+      "dependencies": {
+        "error-stack-parser": "^2.0.6",
+        "stack-generator": "^2.0.5",
+        "stacktrace-gps": "^3.0.4"
+      }
+    },
     "node_modules/stop-iteration-iterator": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz",
@@ -4544,6 +4893,11 @@
         }
       }
     },
+    "node_modules/stylis": {
+      "version": "4.3.3",
+      "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.3.tgz",
+      "integrity": "sha512-VtF42zBHvdPi561i9mAcPlWOUonfbCtXa7qdGI+Ro4qMP8TEb+7GpbGWD1+v2TS4nohQ0m8g1FhTVmRdcIsxdQ=="
+    },
     "node_modules/sucrase": {
       "version": "3.35.0",
       "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
@@ -4672,6 +5026,14 @@
         "node": ">=0.8"
       }
     },
+    "node_modules/throttle-debounce": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-3.0.1.tgz",
+      "integrity": "sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg==",
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/to-regex-range": {
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -4684,6 +5046,11 @@
         "node": ">=8.0"
       }
     },
+    "node_modules/toggle-selection": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
+      "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ=="
+    },
     "node_modules/ts-api-utils": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
@@ -4696,6 +5063,11 @@
         "typescript": ">=4.2.0"
       }
     },
+    "node_modules/ts-easing": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/ts-easing/-/ts-easing-0.2.0.tgz",
+      "integrity": "sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ=="
+    },
     "node_modules/ts-interface-checker": {
       "version": "0.1.13",
       "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
@@ -4880,6 +5252,14 @@
       "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
       "dev": true
     },
+    "node_modules/uuid": {
+      "version": "8.3.2",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+      "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+      "bin": {
+        "uuid": "dist/bin/uuid"
+      }
+    },
     "node_modules/which": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -5083,6 +5463,11 @@
       "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
       "dev": true
     },
+    "node_modules/yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+    },
     "node_modules/yaml": {
       "version": "2.5.0",
       "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz",

+ 2 - 0
package.json

@@ -15,11 +15,13 @@
     "@trpc/server": "^11.0.0-rc.482",
     "jotai": "^2.9.3",
     "next": "14.2.5",
+    "next-auth": "^4.24.7",
     "ramda": "^0.30.1",
     "react": "^18",
     "react-dom": "^18",
     "react-hook-form": "^7.52.2",
     "react-icons": "^5.3.0",
+    "react-use": "^17.5.1",
     "tailwind-merge": "^2.5.2",
     "zod": "^3.23.8"
   },

+ 33 - 11
server/router.ts

@@ -5,17 +5,39 @@ export const appRouter = router({
   ping: publicProcedure.query(async () => {
     return { hello: "world" };
   }),
-  hello: publicProcedure
-    .input(
-      z.object({
-        text: z.string(),
-      })
-    )
-    .query((opts) => {
-      return {
-        greeting: `hello ${opts.input.text}`,
-      };
-    }),
+  org: {
+    bySlug: publicProcedure
+      .input(z.object({ mode: z.string() }))
+      .query(async ({ input: { mode } }) => {
+        if (!mode) return {mail: '', name: ''};
+        const res = await fetch(
+          "https://api.edu.cocorobo.cn/edu/admin/selectorganize",
+          {
+            method: "POST",
+            body: JSON.stringify({ mode }),
+            headers: {
+              "Content-Type": "application/json",
+            },
+          }
+        );
+        const resJson = await res.json();
+        const { mail, name } = resJson?.[0]?.[0];
+        return { mail, name };
+      }),
+  },
+  flowModel: {
+    list: publicProcedure
+      .input(
+        z.object({
+          userId: z.string(),
+        })
+      )
+      .query(async (opts) => {
+        return {
+          greeting: `hello ${opts.input.userId}`,
+        };
+      }),
+  },
   // ...
 });
 

+ 10 - 0
tailwind.config.ts

@@ -9,6 +9,16 @@ const config: Config = {
   theme: {
     extend: {},
   },
+  daisyui: {
+    darkTheme: false,
+    based: true,
+    styled: true,
+    utils: true,
+    prefix: '',
+    logs: true,
+    themes: ["light", "dark", "cupcake"],
+    themeRoot: ":root"
+  },
   plugins: [require("daisyui")],
 };
 export default config;