diff --git a/bun.lockb b/bun.lockb index 7e352b29..b59b19af 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 35e03c42..d7c3b5cb 100644 --- a/package.json +++ b/package.json @@ -16,23 +16,21 @@ "src/email" ], "dependencies": { - "@auth/drizzle-adapter": "^0.3.12", "@headlessui/react": "^1.7.17", - "@planetscale/database": "^1.11.0", "@react-email/render": "^0.0.10", + "@supabase/ssr": "^0.3.0", "@supabase/supabase-js": "^2.42.0", - "@t3-oss/env-nextjs": "^0.7.0", + "@t3-oss/env-nextjs": "^0.9.2", "@tailwindcss/forms": "^0.5.6", - "@tanstack/react-query": "^4.32.6", - "@trpc/client": "^10.37.1", - "@trpc/next": "^10.37.1", - "@trpc/react-query": "^10.37.1", - "@trpc/server": "^10.37.1", + "@tanstack/react-query": "^5.25.0", + "@trpc/client": "next", + "@trpc/next": "next", + "@trpc/react-query": "next", + "@trpc/server": "next", "@vercel/postgres": "^0.7.2", "drizzle-orm": "^0.28.5", "formik": "^2.4.5", - "next": "^13.5.4", - "next-auth": "0.0.0-manual.cfb42ae7", + "next": "^14.1.3", "postgres": "^3.4.4", "react": "18.2.0", "react-beautiful-dnd": "^13.1.1", @@ -45,27 +43,27 @@ "zod": "^3.22.4" }, "devDependencies": { - "@types/eslint": "^8.44.2", - "@types/node": "^18.16.0", - "@types/react": "^18.2.20", + "@types/eslint": "^8.56.2", + "@types/node": "^20.11.20", + "@types/react": "^18.2.57", "@types/react-beautiful-dnd": "^13.1.7", - "@types/react-dom": "^18.2.7", - "@typescript-eslint/eslint-plugin": "^6.3.0", - "@typescript-eslint/parser": "^6.3.0", + "@types/react-dom": "^18.2.19", + "@typescript-eslint/eslint-plugin": "^7.1.1", + "@typescript-eslint/parser": "^7.1.1", "autoprefixer": "^10.4.14", "dotenv-cli": "^7.3.0", "drizzle-kit": "^0.19.13", - "eslint": "^8.47.0", - "eslint-config-next": "^13.5.4", - "mysql2": "^3.6.1", - "postcss": "^8.4.27", - "prettier": "^3.0.0", - "prettier-plugin-tailwindcss": "^0.5.1", + "eslint": "^8.57.0", + "eslint-config-next": "^14.1.3", + "pg": "^8.11.3", + "postcss": "^8.4.34", + "prettier": "^3.2.5", + "prettier-plugin-tailwindcss": "^0.5.11", "supabase": "^1.153.4", "tailwind": "^4.0.0", "tailwind-scrollbar": "^3.0.5", - "tailwindcss": "^3.3.3", - "typescript": "^5.1.6" + "tailwindcss": "^3.4.1", + "typescript": "^5.4.2" }, "ct3aMetadata": { "initVersion": "7.22.0" diff --git a/src/app/api/auth/[...nextauth]/route.ts b/src/app/api/auth/[...nextauth]/route.ts deleted file mode 100644 index d9a057f9..00000000 --- a/src/app/api/auth/[...nextauth]/route.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { GET, POST } from "~/server/auth"; - -export const runtime = "edge"; -export const preferredRegion = 'lhr1'; -export const dynamic = 'force-dynamic' diff --git a/src/app/api/trpc/[trpc]/route.ts b/src/app/api/trpc/[trpc]/route.ts deleted file mode 100644 index 9e63b2d6..00000000 --- a/src/app/api/trpc/[trpc]/route.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; -import { type NextRequest } from "next/server"; - -import { env } from "~/env.mjs"; -import { appRouter } from "~/server/api/root"; -import { createTRPCContext } from "~/server/api/trpc"; - -const handler = (req: NextRequest) => - fetchRequestHandler({ - endpoint: "/api/trpc", - req, - router: appRouter, - createContext: () => createTRPCContext({ req }), - onError: - env.NODE_ENV === "development" - ? ({ path, error }) => { - console.error( - `❌ tRPC failed on ${path ?? ""}: ${error.message}` - ); - } - : undefined, - }); - -export { handler as GET, handler as POST }; - -export const runtime = "edge"; -export const preferredRegion = 'lhr1'; -export const dynamic = 'force-dynamic' diff --git a/src/app/boards/layout.tsx b/src/app/boards/layout.tsx deleted file mode 100644 index 41d7017b..00000000 --- a/src/app/boards/layout.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { WorkspaceProvider } from "~/app/providers/workspace"; -import Dashboard from "~/app/components/dashboard"; - -export default function Layout(props: { children: React.ReactNode }) { - return ( - - {props.children} - - ); -} diff --git a/src/app/cards/layout.tsx b/src/app/cards/layout.tsx deleted file mode 100644 index 09288909..00000000 --- a/src/app/cards/layout.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { WorkspaceProvider } from "~/app/providers/workspace"; -import Dashboard from "~/app/components/dashboard"; - -export default function Layout(props: { children: React.ReactNode }) { - return ( - - {props.children}; - - ); -} diff --git a/src/app/layout.tsx b/src/app/layout.tsx deleted file mode 100644 index 7f18d142..00000000 --- a/src/app/layout.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import "~/styles/globals.css"; - -import { Plus_Jakarta_Sans } from "next/font/google"; -import { headers } from "next/headers"; - -import { TRPCReactProvider } from "~/trpc/react"; -import { ModalProvider } from "~/app/providers/modal"; -import { BoardProvider } from "~/app/providers/board"; -import { ThemeProvider } from "./providers/theme"; - -const jakarta = Plus_Jakarta_Sans({ - subsets: ["latin"], - display: "swap", - variable: "--font-plus-jakarta-sans", -}); - -export const metadata = { - title: "Kan", - description: "The open source Trello alternative", - icons: [{ rel: "icon", url: "/favicon.ico" }], -}; - -export default function RootLayout({ - children, -}: { - children: React.ReactNode; -}) { - return ( - - - - - - {children} - - - - - - ); -} diff --git a/src/app/members/layout.tsx b/src/app/members/layout.tsx deleted file mode 100644 index 09288909..00000000 --- a/src/app/members/layout.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { WorkspaceProvider } from "~/app/providers/workspace"; -import Dashboard from "~/app/components/dashboard"; - -export default function Layout(props: { children: React.ReactNode }) { - return ( - - {props.children}; - - ); -} diff --git a/src/app/page.tsx b/src/app/page.tsx deleted file mode 100644 index 7bff2ad8..00000000 --- a/src/app/page.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function Home() { - return
; -} diff --git a/src/app/settings/layout.tsx b/src/app/settings/layout.tsx deleted file mode 100644 index 09288909..00000000 --- a/src/app/settings/layout.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { WorkspaceProvider } from "~/app/providers/workspace"; -import Dashboard from "~/app/components/dashboard"; - -export default function Layout(props: { children: React.ReactNode }) { - return ( - - {props.children}; - - ); -} diff --git a/src/app/assets/boards-dark.json b/src/assets/boards-dark.json similarity index 100% rename from src/app/assets/boards-dark.json rename to src/assets/boards-dark.json diff --git a/src/app/assets/boards-light.json b/src/assets/boards-light.json similarity index 100% rename from src/app/assets/boards-light.json rename to src/assets/boards-light.json diff --git a/src/app/assets/chat-dark.json b/src/assets/chat-dark.json similarity index 100% rename from src/app/assets/chat-dark.json rename to src/assets/chat-dark.json diff --git a/src/app/assets/chat-light.json b/src/assets/chat-light.json similarity index 100% rename from src/app/assets/chat-light.json rename to src/assets/chat-light.json diff --git a/src/app/assets/members-dark.json b/src/assets/members-dark.json similarity index 100% rename from src/app/assets/members-dark.json rename to src/assets/members-dark.json diff --git a/src/app/assets/members-light.json b/src/assets/members-light.json similarity index 100% rename from src/app/assets/members-light.json rename to src/assets/members-light.json diff --git a/src/app/assets/settings-dark.json b/src/assets/settings-dark.json similarity index 100% rename from src/app/assets/settings-dark.json rename to src/assets/settings-dark.json diff --git a/src/app/assets/settings-light.json b/src/assets/settings-light.json similarity index 100% rename from src/app/assets/settings-light.json rename to src/assets/settings-light.json diff --git a/src/app/components/CheckboxDropdown.tsx b/src/components/CheckboxDropdown.tsx similarity index 87% rename from src/app/components/CheckboxDropdown.tsx rename to src/components/CheckboxDropdown.tsx index 2e7381b4..48c5da67 100644 --- a/src/app/components/CheckboxDropdown.tsx +++ b/src/components/CheckboxDropdown.tsx @@ -1,5 +1,3 @@ -"use client"; - import { Fragment } from "react"; import { Menu, Transition } from "@headlessui/react"; @@ -35,13 +33,13 @@ export default function CheckboxDropdown({ leaveFrom="transform opacity-100 scale-100" leaveTo="transform opacity-0 scale-95" > - +
{items?.map((item) => (
{ e.preventDefault(); handleSelect({ key: item.key }); diff --git a/src/app/components/FeedbackButton.tsx b/src/components/FeedbackButton.tsx similarity index 66% rename from src/app/components/FeedbackButton.tsx rename to src/components/FeedbackButton.tsx index 40775b42..1ad26bc0 100644 --- a/src/app/components/FeedbackButton.tsx +++ b/src/components/FeedbackButton.tsx @@ -1,11 +1,9 @@ -"use client"; - import { useState } from "react"; -import { useTheme } from "~/app/providers/theme"; +import { useTheme } from "~/providers/theme"; -import LottieIcon from "~/app/components/LottieIcon"; -import chatIconLight from "~/app/assets/chat-light.json"; -import chatIconDark from "~/app/assets/chat-dark.json"; +import LottieIcon from "~/components/LottieIcon"; +import chatIconLight from "~/assets/chat-light.json"; +import chatIconDark from "~/assets/chat-dark.json"; const FeedbackButton: React.FC = () => { const { theme } = useTheme(); @@ -21,7 +19,7 @@ const FeedbackButton: React.FC = () => { diff --git a/src/app/components/WorkspaceMenu.tsx b/src/components/WorkspaceMenu.tsx similarity index 77% rename from src/app/components/WorkspaceMenu.tsx rename to src/components/WorkspaceMenu.tsx index 46100313..41b20483 100644 --- a/src/app/components/WorkspaceMenu.tsx +++ b/src/components/WorkspaceMenu.tsx @@ -1,10 +1,8 @@ -"use client"; - import { Fragment } from "react"; import { Menu, Transition } from "@headlessui/react"; -import { useModal } from "~/app/providers/modal"; -import { useWorkspace } from "~/app/providers/workspace"; +import { useModal } from "~/providers/modal"; +import { useWorkspace } from "~/providers/workspace"; import { HiCheck } from "react-icons/hi2"; @@ -15,7 +13,7 @@ export default function WorkspaceMenu() { return (
- + {workspace?.name.charAt(0).toUpperCase()} @@ -36,14 +34,14 @@ export default function WorkspaceMenu() { leaveFrom="transform opacity-100 scale-100" leaveTo="transform opacity-0 scale-95" > - +
{availableWorkspaces.map((availableWorkspace) => (
-
+
diff --git a/src/app/components/auth.tsx b/src/components/auth.tsx similarity index 96% rename from src/app/components/auth.tsx rename to src/components/auth.tsx index 2ff66ee4..a4f97b0a 100644 --- a/src/app/components/auth.tsx +++ b/src/components/auth.tsx @@ -1,7 +1,5 @@ -"use client"; - import { Formik, Form, Field } from "formik"; -import { api } from "~/trpc/react"; +import { api } from "~/utils/api"; interface FormValues { email: string; diff --git a/src/app/components/dashboard.tsx b/src/components/dashboard.tsx similarity index 53% rename from src/app/components/dashboard.tsx rename to src/components/dashboard.tsx index a17a5902..53e6bcf6 100644 --- a/src/app/components/dashboard.tsx +++ b/src/components/dashboard.tsx @@ -1,20 +1,18 @@ import { redirect } from "next/navigation"; -import { auth } from "~/server/auth"; - import SideNavigation from "./SideNavigation"; import FeedbackButton from "./FeedbackButton"; -export default async function Dashboard(props: { children: React.ReactNode }) { - const session = await auth(); +export default function Dashboard(props: { children: React.ReactNode }) { + // const session = await auth(); - if (!session?.user) { - redirect("/api/auth/signin"); - } + // if (!session?.user) { + // redirect("/api/auth/signin"); + // } return ( -
-
+
+

kan.bn @@ -24,9 +22,9 @@ export default async function Dashboard(props: { children: React.ReactNode }) {

- +
{props.children}
-
+
); } diff --git a/src/app/components/modal.tsx b/src/components/modal.tsx similarity index 80% rename from src/app/components/modal.tsx rename to src/components/modal.tsx index a343eeb5..de672f10 100644 --- a/src/app/components/modal.tsx +++ b/src/components/modal.tsx @@ -1,9 +1,7 @@ -"use client"; - import { Fragment } from "react"; import { Dialog, Transition } from "@headlessui/react"; -import { useModal } from "~/app/providers/modal"; +import { useModal } from "~/providers/modal"; interface Props { children: React.ReactNode; @@ -24,7 +22,7 @@ const Modal: React.FC = ({ children }) => { leaveFrom="opacity-100" leaveTo="opacity-0" > -
+
@@ -38,7 +36,7 @@ const Modal: React.FC = ({ children }) => { leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" > - + {children} diff --git a/src/env.mjs b/src/env.mjs index 06896a09..8c2e6b00 100644 --- a/src/env.mjs +++ b/src/env.mjs @@ -17,17 +17,6 @@ export const env = createEnv({ NODE_ENV: z .enum(["development", "test", "production"]) .default("development"), - NEXTAUTH_SECRET: - process.env.NODE_ENV === "production" - ? z.string() - : z.string().optional(), - NEXTAUTH_URL: z.preprocess( - // This makes Vercel deployments not fail if you don't set NEXTAUTH_URL - // Since NextAuth.js automatically uses the VERCEL_URL if present. - (str) => process.env.VERCEL_URL ?? str, - // VERCEL_URL doesn't include `https` so it cant be validated as a URL - process.env.VERCEL ? z.string() : z.string().url(), - ), }, /** @@ -46,8 +35,7 @@ export const env = createEnv({ runtimeEnv: { POSTGRES_URL: process.env.POSTGRES_URL, NODE_ENV: process.env.NODE_ENV, - NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET, - NEXTAUTH_URL: process.env.NEXTAUTH_URL, + // NEXT_PUBLIC_CLIENTVAR: process.env.NEXT_PUBLIC_CLIENTVAR, }, /** * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially @@ -55,8 +43,8 @@ export const env = createEnv({ */ skipValidation: !!process.env.SKIP_ENV_VALIDATION, /** - * Makes it so that empty strings are treated as undefined. - * `SOME_VAR: z.string()` and `SOME_VAR=''` will throw an error. + * Makes it so that empty strings are treated as undefined. `SOME_VAR: z.string()` and + * `SOME_VAR=''` will throw an error. */ emptyStringAsUndefined: true, }); diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx new file mode 100644 index 00000000..f2ac059b --- /dev/null +++ b/src/pages/_app.tsx @@ -0,0 +1,38 @@ +import "~/styles/globals.css"; + +import { type AppType } from "next/app"; +import { Plus_Jakarta_Sans } from "next/font/google"; + +import { ModalProvider } from "~/providers/modal"; +import { BoardProvider } from "~/providers/board"; +import { ThemeProvider } from "~/providers/theme"; + +import { api } from "~/utils/api"; + +const jakarta = Plus_Jakarta_Sans({ + subsets: ["latin"], + display: "swap", + variable: "--font-plus-jakarta-sans", +}); + +export const metadata = { + title: "Kan", + description: "The open source Trello alternative", + icons: [{ rel: "icon", url: "/favicon.ico" }], +}; + +const MyApp: AppType = ({ Component, pageProps }) => { + return ( +
+ + + + + + + +
+ ); +}; + +export default api.withTRPC(MyApp); diff --git a/src/pages/api/auth/confirm.ts b/src/pages/api/auth/confirm.ts new file mode 100644 index 00000000..ae4c40ae --- /dev/null +++ b/src/pages/api/auth/confirm.ts @@ -0,0 +1,36 @@ +import { type EmailOtpType } from '@supabase/supabase-js' +import type { NextApiRequest, NextApiResponse } from 'next' + +import createClient from '~/utils/supabase/api' + +function stringOrFirstString(item: string | string[] | undefined) { + return Array.isArray(item) ? item[0] : item +} + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + if (req.method !== 'GET') { + res.status(405).appendHeader('Allow', 'GET').end() + return + } + + const queryParams = req.query + const token_hash = stringOrFirstString(queryParams.token_hash) + const type = stringOrFirstString(queryParams.type) + + let next = '/error' + + if (token_hash && type) { + const supabase = createClient(req, res) + const { error } = await supabase.auth.verifyOtp({ + type: type as EmailOtpType, + token_hash, + }) + if (error) { + console.error(error) + } else { + next = stringOrFirstString(queryParams.next) || '/' + } + } + + res.redirect(next) +} \ No newline at end of file diff --git a/src/pages/api/trpc/[trpc].ts b/src/pages/api/trpc/[trpc].ts new file mode 100644 index 00000000..84c02f2a --- /dev/null +++ b/src/pages/api/trpc/[trpc].ts @@ -0,0 +1,33 @@ +import { NextApiRequest, NextApiResponse } from 'next'; +import { createNextApiHandler, CreateNextContextOptions } from "@trpc/server/adapters/next"; + +import { env } from "~/env.mjs"; +import { appRouter } from "~/server/api/root"; +import { createTRPCContext } from "~/server/api/trpc"; + + +const nextApiHandler = createNextApiHandler({ + router: appRouter, + createContext: createTRPCContext, + onError: + env.NODE_ENV === "development" + ? ({ path, error }) => { + console.error( + `❌ tRPC failed on ${path ?? ""}: ${error.message}` + ); + } + : undefined, +}); + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse, +) { + + return nextApiHandler(req, res); +} + +// export const runtime = "edge"; +// export const preferredRegion = 'lhr1'; +// export const dynamic = 'force-dynamic' + diff --git a/src/pages/boards/[...boardId]/index.tsx b/src/pages/boards/[...boardId]/index.tsx new file mode 100644 index 00000000..a249463f --- /dev/null +++ b/src/pages/boards/[...boardId]/index.tsx @@ -0,0 +1,13 @@ +import { WorkspaceProvider } from "~/providers/workspace"; +import Dashboard from "~/components/dashboard"; +import BoardView from "~/views/board"; + +export default function BoardPage() { + return ( + + + + + + ); +} diff --git a/src/pages/boards/index.tsx b/src/pages/boards/index.tsx new file mode 100644 index 00000000..2c8beb9a --- /dev/null +++ b/src/pages/boards/index.tsx @@ -0,0 +1,13 @@ +import { WorkspaceProvider } from "~/providers/workspace"; +import Dashboard from "~/components/dashboard"; +import BoardsView from "~/views/boards"; + +export default function BoardsPage() { + return ( + + + + + + ); +} diff --git a/src/pages/cards/[cardId]/index.tsx b/src/pages/cards/[cardId]/index.tsx new file mode 100644 index 00000000..bd91b2b9 --- /dev/null +++ b/src/pages/cards/[cardId]/index.tsx @@ -0,0 +1,13 @@ +import { WorkspaceProvider } from "~/providers/workspace"; +import Dashboard from "~/components/dashboard"; +import CardView from "~/views/card"; + +export default function CardPage() { + return ( + + + + + + ); +} diff --git a/src/pages/login/index.tsx b/src/pages/login/index.tsx new file mode 100644 index 00000000..1794079a --- /dev/null +++ b/src/pages/login/index.tsx @@ -0,0 +1,5 @@ +import LoginView from "~/views/auth/login"; + +export default function LoginPage() { + return ; +} diff --git a/src/pages/members/index.tsx b/src/pages/members/index.tsx new file mode 100644 index 00000000..6736584e --- /dev/null +++ b/src/pages/members/index.tsx @@ -0,0 +1,13 @@ +import { WorkspaceProvider } from "~/providers/workspace"; +import Dashboard from "~/components/dashboard"; +import MembersView from "~/views/members"; + +export default function MembersPage() { + return ( + + + + + + ); +} diff --git a/src/pages/settings/index.tsx b/src/pages/settings/index.tsx new file mode 100644 index 00000000..280e6654 --- /dev/null +++ b/src/pages/settings/index.tsx @@ -0,0 +1,13 @@ +import { WorkspaceProvider } from "~/providers/workspace"; +import Dashboard from "~/components/dashboard"; +import SettingsView from "~/views/settings"; + +export default function SettingsPage() { + return ( + + + + + + ); +} diff --git a/src/app/providers/board.tsx b/src/providers/board.tsx similarity index 98% rename from src/app/providers/board.tsx rename to src/providers/board.tsx index 58e439c5..2e335ddd 100644 --- a/src/app/providers/board.tsx +++ b/src/providers/board.tsx @@ -1,5 +1,3 @@ -"use client"; - import React, { createContext, useContext, @@ -7,7 +5,7 @@ import React, { type ReactNode, } from "react"; -import { api } from "~/trpc/react"; +import { api } from "~/utils/api"; interface BoardContextProps { boardData: BoardData; diff --git a/src/app/providers/modal.tsx b/src/providers/modal.tsx similarity index 98% rename from src/app/providers/modal.tsx rename to src/providers/modal.tsx index cf1deaa0..ed9f6f24 100644 --- a/src/app/providers/modal.tsx +++ b/src/providers/modal.tsx @@ -1,5 +1,3 @@ -"use client"; - import { createContext, useContext, useState } from "react"; type ModalContextType = { diff --git a/src/app/providers/theme.tsx b/src/providers/theme.tsx similarity index 99% rename from src/app/providers/theme.tsx rename to src/providers/theme.tsx index 797e2d5a..37c94411 100644 --- a/src/app/providers/theme.tsx +++ b/src/providers/theme.tsx @@ -1,5 +1,3 @@ -"use client"; - import React, { createContext, useContext, diff --git a/src/app/providers/workspace.tsx b/src/providers/workspace.tsx similarity index 98% rename from src/app/providers/workspace.tsx rename to src/providers/workspace.tsx index 5fc9f1f8..e92a9b80 100644 --- a/src/app/providers/workspace.tsx +++ b/src/providers/workspace.tsx @@ -1,5 +1,3 @@ -"use client"; - import React, { createContext, useContext, @@ -8,7 +6,7 @@ import React, { type ReactNode, } from "react"; -import { api } from "~/trpc/react"; +import { api } from "~/utils/api"; import { useRouter } from "next/navigation"; diff --git a/src/server/api/root.ts b/src/server/api/root.ts index 909a7a46..b7c4b71e 100644 --- a/src/server/api/root.ts +++ b/src/server/api/root.ts @@ -24,3 +24,13 @@ export const appRouter = createTRPCRouter({ // export type definition of API export type AppRouter = typeof appRouter; + +/** + * Create a server-side caller for the tRPC API. + * @example + * const trpc = createCaller(createContext); + * const res = await trpc.post.all(); + * ^? Post[] + */ +// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment +// export const createCaller = createCallerFactory(appRouter); \ No newline at end of file diff --git a/src/server/api/trpc.ts b/src/server/api/trpc.ts index 0f72342a..b6f1235a 100644 --- a/src/server/api/trpc.ts +++ b/src/server/api/trpc.ts @@ -6,14 +6,15 @@ * TL;DR - This is where all the tRPC server stuff is created and plugged in. The pieces you will * need to use are documented accordingly near the end. */ - -import { initTRPC, TRPCError } from "@trpc/server"; -import { type NextRequest } from "next/server"; +import { initTRPC } from "@trpc/server"; +import { type CreateNextContextOptions } from "@trpc/server/adapters/next"; import superjson from "superjson"; import { ZodError } from "zod"; -import { auth } from "~/server/auth"; -import { db, supabase } from "~/server/db"; +import { db } from "~/server/db"; +import createClient from "~/utils/supabase/api"; +import { type Database } from "~/types/database.types"; +import { SupabaseClient } from '@supabase/supabase-js'; /** * 1. CONTEXT @@ -23,8 +24,14 @@ import { db, supabase } from "~/server/db"; * These allow you to access things when processing a request, like the database, the session, etc. */ +type User = { + id: string; +}; + interface CreateContextOptions { - headers: Headers; + user: User | null; + supabase: SupabaseClient + db: any; } /** @@ -37,14 +44,12 @@ interface CreateContextOptions { * * @see https://create.t3.gg/en/usage/trpc#-serverapitrpcts */ -export const createInnerTRPCContext = async (opts: CreateContextOptions) => { - const session = await auth(); +export const createInnerTRPCContext = (opts: CreateContextOptions) => { return { - session, - headers: opts.headers, + user: opts.user, + supabase: opts.supabase, db, - supabase }; }; @@ -54,12 +59,12 @@ export const createInnerTRPCContext = async (opts: CreateContextOptions) => { * * @see https://trpc.io/docs/context */ -export const createTRPCContext = async (opts: { req: NextRequest }) => { - // Fetch stuff that depends on the request +export const createTRPCContext = async (_opts: CreateNextContextOptions) => { + const supabase = createClient(_opts.req, _opts.res); - return await createInnerTRPCContext({ - headers: opts.req.headers, - }); + const { data: { user } } = await supabase.auth.getUser() + + return createInnerTRPCContext({ user, supabase }); }; /** @@ -84,6 +89,13 @@ const t = initTRPC.context().create({ }, }); +/** + * Create a server-side caller. + * + * @see https://trpc.io/docs/server/server-side-calls + */ +// export const createCallerFactory = t.createCallerFactory; + /** * 3. ROUTER & PROCEDURE (THE IMPORTANT BIT) * @@ -106,26 +118,3 @@ export const createTRPCRouter = t.router; * are logged in. */ export const publicProcedure = t.procedure; - -/** Reusable middleware that enforces users are logged in before running the procedure. */ -const enforceUserIsAuthed = t.middleware(({ ctx, next }) => { - if (!ctx.session || !ctx.session.user) { - throw new TRPCError({ code: "UNAUTHORIZED" }); - } - return next({ - ctx: { - // infers the `session` as non-nullable - session: { ...ctx.session, user: ctx.session.user }, - }, - }); -}); - -/** - * Protected (authenticated) procedure - * - * If you want a query or mutation to ONLY be accessible to logged in users, use this. It verifies - * the session is valid and guarantees `ctx.session.user` is not null. - * - * @see https://trpc.io/docs/procedures - */ -export const protectedProcedure = t.procedure.use(enforceUserIsAuthed); diff --git a/src/trpc/react.tsx b/src/trpc/react.tsx deleted file mode 100644 index 3e3eb5d8..00000000 --- a/src/trpc/react.tsx +++ /dev/null @@ -1,47 +0,0 @@ -"use client"; - -import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; -import { loggerLink, unstable_httpBatchStreamLink } from "@trpc/client"; -import { createTRPCReact } from "@trpc/react-query"; -import { useState } from "react"; - -import { type AppRouter } from "~/server/api/root"; -import { getUrl, transformer } from "./shared"; - -export const api = createTRPCReact(); - -export function TRPCReactProvider(props: { - children: React.ReactNode; - headers: Headers; -}) { - const [queryClient] = useState(() => new QueryClient()); - - const [trpcClient] = useState(() => - api.createClient({ - transformer, - links: [ - loggerLink({ - enabled: (op) => - process.env.NODE_ENV === "development" || - (op.direction === "down" && op.result instanceof Error), - }), - unstable_httpBatchStreamLink({ - url: getUrl(), - headers() { - const heads = new Map(props.headers); - heads.set("x-trpc-source", "react"); - return Object.fromEntries(heads); - }, - }), - ], - }), - ); - - return ( - - - {props.children} - - - ); -} diff --git a/src/trpc/server.ts b/src/trpc/server.ts deleted file mode 100644 index 6984f458..00000000 --- a/src/trpc/server.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { - createTRPCProxyClient, - loggerLink, - unstable_httpBatchStreamLink, -} from "@trpc/client"; -import { headers } from "next/headers"; - -import { type AppRouter } from "~/server/api/root"; -import { getUrl, transformer } from "./shared"; - -export const api = createTRPCProxyClient({ - transformer, - links: [ - loggerLink({ - enabled: (op) => - process.env.NODE_ENV === "development" || - (op.direction === "down" && op.result instanceof Error), - }), - unstable_httpBatchStreamLink({ - url: getUrl(), - headers() { - const heads = new Map(headers()); - heads.set("x-trpc-source", "rsc"); - return Object.fromEntries(heads); - }, - }), - ], -}); diff --git a/src/trpc/shared.ts b/src/trpc/shared.ts deleted file mode 100644 index 46005045..00000000 --- a/src/trpc/shared.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { type inferRouterInputs, type inferRouterOutputs } from "@trpc/server"; -import superjson from "superjson"; - -import { type AppRouter } from "~/server/api/root"; - -export const transformer = superjson; - -function getBaseUrl() { - if (typeof window !== "undefined") return ""; - if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`; - return `http://localhost:${process.env.PORT ?? 3000}`; -} - -export function getUrl() { - return getBaseUrl() + "/api/trpc"; -} - -/** - * Inference helper for inputs. - * - * @example type HelloInput = RouterInputs['example']['hello'] - */ -export type RouterInputs = inferRouterInputs; - -/** - * Inference helper for outputs. - * - * @example type HelloOutput = RouterOutputs['example']['hello'] - */ -export type RouterOutputs = inferRouterOutputs; diff --git a/src/utils/api.ts b/src/utils/api.ts new file mode 100644 index 00000000..0f03d307 --- /dev/null +++ b/src/utils/api.ts @@ -0,0 +1,68 @@ +/** + * This is the client-side entrypoint for your tRPC API. It is used to create the `api` object which + * contains the Next.js App-wrapper, as well as your type-safe React Query hooks. + * + * We also create a few inference helpers for input and output types. + */ +import { httpBatchLink, loggerLink } from "@trpc/client"; +import { createTRPCNext } from "@trpc/next"; +import { type inferRouterInputs, type inferRouterOutputs } from "@trpc/server"; +import superjson from "superjson"; + +import { type AppRouter } from "~/server/api/root"; + +const getBaseUrl = () => { + if (typeof window !== "undefined") return ""; // browser should use relative url + if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`; // SSR should use vercel url + return `http://localhost:${process.env.PORT ?? 3000}`; // dev SSR should use localhost +}; + +/** A set of type-safe react-query hooks for your tRPC API. */ +export const api = createTRPCNext({ + config() { + return { + /** + * Links used to determine request flow from client to server. + * + * @see https://trpc.io/docs/links + */ + links: [ + loggerLink({ + enabled: (opts) => + process.env.NODE_ENV === "development" || + (opts.direction === "down" && opts.result instanceof Error), + }), + httpBatchLink({ + /** + * Transformer used for data de-serialization from the server. + * + * @see https://trpc.io/docs/data-transformers + */ + transformer: superjson, + url: `${getBaseUrl()}/api/trpc`, + }), + ], + }; + }, + /** + * Whether tRPC should await queries when server rendering pages. + * + * @see https://trpc.io/docs/nextjs#ssr-boolean-default-false + */ + ssr: false, + transformer: superjson, +}); + +/** + * Inference helper for inputs. + * + * @example type HelloInput = RouterInputs['example']['hello'] + */ +export type RouterInputs = inferRouterInputs; + +/** + * Inference helper for outputs. + * + * @example type HelloOutput = RouterOutputs['example']['hello'] + */ +export type RouterOutputs = inferRouterOutputs; diff --git a/src/app/auth/login/page.tsx b/src/views/auth/login/index.tsx similarity index 93% rename from src/app/auth/login/page.tsx rename to src/views/auth/login/index.tsx index 1a036b9a..d1226beb 100644 --- a/src/app/auth/login/page.tsx +++ b/src/views/auth/login/index.tsx @@ -1,4 +1,4 @@ -import { Login } from "~/app/components/auth"; +import { Login } from "~/components/auth"; export default function LoginPage() { return ( diff --git a/src/app/auth/verify/page.tsx b/src/views/auth/verify/index.tsx similarity index 100% rename from src/app/auth/verify/page.tsx rename to src/views/auth/verify/index.tsx diff --git a/src/app/boards/[...boardId]/components/BoardDropdown.tsx b/src/views/board/components/BoardDropdown.tsx similarity index 73% rename from src/app/boards/[...boardId]/components/BoardDropdown.tsx rename to src/views/board/components/BoardDropdown.tsx index 3995c84e..aecb67ce 100644 --- a/src/app/boards/[...boardId]/components/BoardDropdown.tsx +++ b/src/views/board/components/BoardDropdown.tsx @@ -1,9 +1,7 @@ -"use client"; - import { Fragment } from "react"; import { Menu, Transition } from "@headlessui/react"; import { HiEllipsisHorizontal } from "react-icons/hi2"; -import { useModal } from "~/app/providers/modal"; +import { useModal } from "~/providers/modal"; export default function BoardDropdown() { const { openModal } = useModal(); @@ -11,7 +9,7 @@ export default function BoardDropdown() { return (
- + - +
diff --git a/src/app/boards/[...boardId]/components/DeleteBoardConfirmation.tsx b/src/views/board/components/DeleteBoardConfirmation.tsx similarity index 72% rename from src/app/boards/[...boardId]/components/DeleteBoardConfirmation.tsx rename to src/views/board/components/DeleteBoardConfirmation.tsx index 060c81d8..07f72337 100644 --- a/src/app/boards/[...boardId]/components/DeleteBoardConfirmation.tsx +++ b/src/views/board/components/DeleteBoardConfirmation.tsx @@ -1,10 +1,8 @@ -"use client"; - import { useRouter } from "next/navigation"; -import { api } from "~/trpc/react"; -import { useBoard } from "~/app/providers/board"; -import { useModal } from "~/app/providers/modal"; +import { api } from "~/utils/api"; +import { useBoard } from "~/providers/board"; +import { useModal } from "~/providers/modal"; export function DeleteBoardConfirmation() { const router = useRouter(); @@ -24,13 +22,13 @@ export function DeleteBoardConfirmation() {

Are you sure you want to delete this board?

-

+

{"This action can't be undone."}

diff --git a/src/app/boards/[...boardId]/components/DeleteListConfirmation.tsx b/src/views/board/components/DeleteListConfirmation.tsx similarity index 74% rename from src/app/boards/[...boardId]/components/DeleteListConfirmation.tsx rename to src/views/board/components/DeleteListConfirmation.tsx index 65f4da50..0b8f1d34 100644 --- a/src/app/boards/[...boardId]/components/DeleteListConfirmation.tsx +++ b/src/views/board/components/DeleteListConfirmation.tsx @@ -1,8 +1,6 @@ -"use client"; - -import { api } from "~/trpc/react"; -import { useBoard } from "~/app/providers/board"; -import { useModal } from "~/app/providers/modal"; +import { api } from "~/utils/api"; +import { useBoard } from "~/providers/board"; +import { useModal } from "~/providers/modal"; interface DeleteListConfirmationProps { listPublicId: string; @@ -31,13 +29,13 @@ export function DeleteListConfirmation({

Are you sure you want to delete this list?

-

+

{"This action can't be undone."}

diff --git a/src/app/boards/[...boardId]/components/List.tsx b/src/views/board/components/List.tsx similarity index 87% rename from src/app/boards/[...boardId]/components/List.tsx rename to src/views/board/components/List.tsx index 69677d13..23c5879d 100644 --- a/src/app/boards/[...boardId]/components/List.tsx +++ b/src/views/board/components/List.tsx @@ -1,12 +1,10 @@ -"use client"; - import { type ReactNode } from "react"; import { HiOutlinePlusSmall } from "react-icons/hi2"; import { Draggable } from "react-beautiful-dnd"; import { useFormik } from "formik"; -import { api } from "~/trpc/react"; -import { useModal } from "~/app/providers/modal"; +import { api } from "~/utils/api"; +import { useModal } from "~/providers/modal"; import ListDropdown from "./ListDropdown"; @@ -66,7 +64,7 @@ export default function List({ ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps} - className="bg-light-300 border-light-400 dark-text-dark-1000 mr-5 h-fit min-w-[18rem] max-w-[18rem] rounded-md border py-2 pl-2 pr-1 text-neutral-900 dark:border-dark-400 dark:bg-dark-200" + className="dark-text-dark-1000 mr-5 h-fit min-w-[18rem] max-w-[18rem] rounded-md border border-light-400 bg-light-300 py-2 pl-2 pr-1 text-neutral-900 dark:border-dark-400 dark:bg-dark-200" >
diff --git a/src/app/boards/[...boardId]/components/NewCardForm.tsx b/src/views/board/components/NewCardForm.tsx similarity index 86% rename from src/app/boards/[...boardId]/components/NewCardForm.tsx rename to src/views/board/components/NewCardForm.tsx index cfc8fd83..e94e45b3 100644 --- a/src/app/boards/[...boardId]/components/NewCardForm.tsx +++ b/src/views/board/components/NewCardForm.tsx @@ -1,15 +1,13 @@ -"use client"; - import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; -import { api } from "~/trpc/react"; +import { api } from "~/utils/api"; import { HiXMark } from "react-icons/hi2"; import { Switch } from "@headlessui/react"; -import CheckboxDropdown from "~/app/components/CheckboxDropdown"; -import { useBoard } from "~/app/providers/board"; -import { useModal } from "~/app/providers/modal"; +import CheckboxDropdown from "~/components/CheckboxDropdown"; +import { useBoard } from "~/providers/board"; +import { useModal } from "~/providers/modal"; interface FormData { title: string; @@ -142,7 +140,7 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) { New card
@@ -172,7 +170,7 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) { handleSelectList(list.key) } > -
+
{selectedList?.value}
@@ -184,7 +182,7 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) { handleSelectMembers(list.key) } > -
+
{!memberPublicIds.length ? ( "Members" ) : ( @@ -197,7 +195,7 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) { return ( {member?.value @@ -222,7 +220,7 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) { handleSelectLabels(list.key) } > -
+
{!labelPublicIds.length ? ( "Labels" ) : ( @@ -267,7 +265,7 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) {
- + Create more diff --git a/src/app/boards/[...boardId]/components/NewListForm.tsx b/src/views/board/components/NewListForm.tsx similarity index 82% rename from src/app/boards/[...boardId]/components/NewListForm.tsx rename to src/views/board/components/NewListForm.tsx index 3f384f15..edbbde05 100644 --- a/src/app/boards/[...boardId]/components/NewListForm.tsx +++ b/src/views/board/components/NewListForm.tsx @@ -1,13 +1,11 @@ -"use client"; - import { useState, useEffect } from "react"; -import { api } from "~/trpc/react"; +import { api } from "~/utils/api"; import { HiXMark } from "react-icons/hi2"; import { Switch } from "@headlessui/react"; -import { useBoard } from "~/app/providers/board"; -import { useModal } from "~/app/providers/modal"; +import { useBoard } from "~/providers/board"; +import { useModal } from "~/providers/modal"; import { Formik, Form, Field } from "formik"; @@ -56,7 +54,7 @@ export function NewListForm({ boardPublicId }: boardPublicId) { New list diff --git a/src/app/boards/[...boardId]/page.tsx b/src/views/board/index.tsx similarity index 97% rename from src/app/boards/[...boardId]/page.tsx rename to src/views/board/index.tsx index 0923c023..9535e47c 100644 --- a/src/app/boards/[...boardId]/page.tsx +++ b/src/views/board/index.tsx @@ -1,5 +1,3 @@ -"use client"; - import { useState } from "react"; import Link from "next/link"; import { useParams } from "next/navigation"; @@ -12,17 +10,17 @@ import { } from "react-beautiful-dnd"; import { useFormik } from "formik"; -import { api } from "~/trpc/react"; -import { useBoard } from "~/app/providers/board"; -import { useModal } from "~/app/providers/modal"; +import { api } from "~/utils/api"; +import { useBoard } from "~/providers/board"; +import { useModal } from "~/providers/modal"; -import Modal from "~/app/components/modal"; +import Modal from "~/components/modal"; import BoardDropdown from "./components/BoardDropdown"; import { DeleteBoardConfirmation } from "./components/DeleteBoardConfirmation"; import { DeleteListConfirmation } from "./components/DeleteListConfirmation"; import List from "./components/List"; -import { NewWorkspaceForm } from "~/app/components/NewWorkspaceForm"; +import { NewWorkspaceForm } from "~/components/NewWorkspaceForm"; import { NewCardForm } from "./components/NewCardForm"; import { NewListForm } from "./components/NewListForm"; diff --git a/src/app/boards/components/BoardsList.tsx b/src/views/boards/components/BoardsList.tsx similarity index 95% rename from src/app/boards/components/BoardsList.tsx rename to src/views/boards/components/BoardsList.tsx index d6f588ee..b07483b6 100644 --- a/src/app/boards/components/BoardsList.tsx +++ b/src/views/boards/components/BoardsList.tsx @@ -1,9 +1,7 @@ -"use client"; - import Link from "next/link"; -import { api } from "~/trpc/react"; -import { useWorkspace } from "~/app/providers/workspace"; +import { api } from "~/utils/api"; +import { useWorkspace } from "~/providers/workspace"; export function BoardsList() { const { workspace } = useWorkspace(); diff --git a/src/app/boards/components/ImportBoardsForm.tsx b/src/views/boards/components/ImportBoardsForm.tsx similarity index 84% rename from src/app/boards/components/ImportBoardsForm.tsx rename to src/views/boards/components/ImportBoardsForm.tsx index 2c449d75..67d522b1 100644 --- a/src/app/boards/components/ImportBoardsForm.tsx +++ b/src/views/boards/components/ImportBoardsForm.tsx @@ -1,14 +1,12 @@ -"use client"; - import { Fragment, useState } from "react"; -import { api } from "~/trpc/react"; +import { api } from "~/utils/api"; import { Listbox, Transition } from "@headlessui/react"; import { FaTrello } from "react-icons/fa"; import { HiChevronUpDown, HiXMark } from "react-icons/hi2"; -import { useModal } from "~/app/providers/modal"; -import { useWorkspace } from "~/app/providers/workspace"; +import { useModal } from "~/providers/modal"; +import { useWorkspace } from "~/providers/workspace"; import { useFormik } from "formik"; @@ -41,7 +39,7 @@ const SelectSource = ({ handleNextStep }: { handleNextStep: () => void }) => { {({ open }) => ( <>
- + @@ -63,14 +61,14 @@ const SelectSource = ({ handleNextStep }: { handleNextStep: () => void }) => { leaveFrom="opacity-100" leaveTo="opacity-0" > - + {sources.map(({ source }, index) => ( -
+
{source} @@ -87,7 +85,7 @@ const SelectSource = ({ handleNextStep }: { handleNextStep: () => void }) => {
@@ -219,7 +217,7 @@ const ImportTrello: React.FC = () => { @@ -232,14 +230,14 @@ const ImportTrello: React.FC = () => {
@@ -259,7 +257,7 @@ export function ImportBoardsForm() { New import diff --git a/src/app/boards/page.tsx b/src/views/boards/index.tsx similarity index 81% rename from src/app/boards/page.tsx rename to src/views/boards/index.tsx index 4c67bf4b..0e1f4270 100644 --- a/src/app/boards/page.tsx +++ b/src/views/boards/index.tsx @@ -1,14 +1,12 @@ -"use client"; - import { HiArrowDownTray, HiOutlinePlusSmall } from "react-icons/hi2"; import { BoardsList } from "./components/BoardsList"; -import { useModal } from "~/app/providers/modal"; -import Modal from "~/app/components/modal"; +import { useModal } from "~/providers/modal"; +import Modal from "~/components/modal"; import { ImportBoardsForm } from "./components/ImportBoardsForm"; import { NewBoardForm } from "./components/NewBoardForm"; -import { NewWorkspaceForm } from "~/app/components/NewWorkspaceForm"; +import { NewWorkspaceForm } from "~/components/NewWorkspaceForm"; export default function BoardsPage() { const { openModal, modalContentType } = useModal(); @@ -22,7 +20,7 @@ export default function BoardsPage() {
diff --git a/src/app/cards/[cardId]/components/Dropdown.tsx b/src/views/card/components/Dropdown.tsx similarity index 73% rename from src/app/cards/[cardId]/components/Dropdown.tsx rename to src/views/card/components/Dropdown.tsx index deb9dee1..c23a01b2 100644 --- a/src/app/cards/[cardId]/components/Dropdown.tsx +++ b/src/views/card/components/Dropdown.tsx @@ -1,9 +1,7 @@ -"use client"; - import { Fragment } from "react"; import { Menu, Transition } from "@headlessui/react"; import { HiEllipsisHorizontal } from "react-icons/hi2"; -import { useModal } from "~/app/providers/modal"; +import { useModal } from "~/providers/modal"; export default function Dropdown() { const { openModal } = useModal(); @@ -11,7 +9,7 @@ export default function Dropdown() { return (
- + - +
diff --git a/src/app/cards/[cardId]/components/LabelSelector.tsx b/src/views/card/components/LabelSelector.tsx similarity index 80% rename from src/app/cards/[cardId]/components/LabelSelector.tsx rename to src/views/card/components/LabelSelector.tsx index db21f180..8064d9b1 100644 --- a/src/app/cards/[cardId]/components/LabelSelector.tsx +++ b/src/views/card/components/LabelSelector.tsx @@ -1,12 +1,10 @@ -"use client"; - import { Fragment } from "react"; -import { api } from "~/trpc/react"; +import { api } from "~/utils/api"; import { Menu, Transition } from "@headlessui/react"; import { HiMiniPlus } from "react-icons/hi2"; import { useFormik } from "formik"; -import { useModal } from "~/app/providers/modal"; +import { useModal } from "~/providers/modal"; interface LabelSelectorProps { cardPublicId: string; @@ -58,7 +56,7 @@ export default function LabelSelector({ {selectedLabels.map((label) => ( {label.name}
))} - + Add label ) : ( - + Add label @@ -92,7 +90,7 @@ export default function LabelSelector({ leaveFrom="transform opacity-100 scale-100" leaveTo="transform opacity-0 scale-95" > - +
{labels?.map((label) => ( @@ -100,7 +98,7 @@ export default function LabelSelector({ {() => (
{ e.preventDefault(); await formik.setFieldValue( @@ -137,7 +135,7 @@ export default function LabelSelector({ ))} diff --git a/src/app/cards/[cardId]/page.tsx b/src/views/card/index.tsx similarity index 88% rename from src/app/cards/[cardId]/page.tsx rename to src/views/card/index.tsx index 3efb6351..4ac2c141 100644 --- a/src/app/cards/[cardId]/page.tsx +++ b/src/views/card/index.tsx @@ -1,5 +1,3 @@ -"use client"; - import Link from "next/link"; import { useParams } from "next/navigation"; import { useFormik } from "formik"; @@ -12,12 +10,12 @@ import LabelSelector from "./components/LabelSelector"; import ListSelector from "./components/ListSelector"; import MemberSelector from "./components/MemberSelector"; import { NewLabelForm } from "./components/NewLabelForm"; -import { NewWorkspaceForm } from "~/app/components/NewWorkspaceForm"; +import { NewWorkspaceForm } from "~/components/NewWorkspaceForm"; -import Modal from "~/app/components/modal"; -import { useModal } from "~/app/providers/modal"; +import Modal from "~/components/modal"; +import { useModal } from "~/providers/modal"; -import { api } from "~/trpc/react"; +import { api } from "~/utils/api"; interface FormValues { cardId: string; @@ -98,14 +96,14 @@ export default function CardPage() {
{board?.name}
@@ -135,13 +133,13 @@ export default function CardPage() { formik.setFieldValue("description", e.target.value) } onBlur={formik.submitForm} - className="text-light-900 block w-full border-0 bg-transparent py-1.5 focus-visible:outline-none dark:text-dark-1000 sm:text-sm sm:leading-6" + className="block w-full border-0 bg-transparent py-1.5 text-light-900 focus-visible:outline-none dark:text-dark-1000 sm:text-sm sm:leading-6" />
-
+

List

diff --git a/src/app/members/components/MemberDropdown.tsx b/src/views/members/components/MemberDropdown.tsx similarity index 100% rename from src/app/members/components/MemberDropdown.tsx rename to src/views/members/components/MemberDropdown.tsx diff --git a/src/app/members/page.tsx b/src/views/members/index.tsx similarity index 80% rename from src/app/members/page.tsx rename to src/views/members/index.tsx index dd6a28f5..a20407b5 100644 --- a/src/app/members/page.tsx +++ b/src/views/members/index.tsx @@ -1,13 +1,11 @@ -"use client"; - import { HiOutlinePlusSmall } from "react-icons/hi2"; -import { useModal } from "~/app/providers/modal"; -import { useWorkspace } from "~/app/providers/workspace"; -import Modal from "~/app/components/modal"; +import { useModal } from "~/providers/modal"; +import { useWorkspace } from "~/providers/workspace"; +import Modal from "~/components/modal"; -import { NewWorkspaceForm } from "~/app/components/NewWorkspaceForm"; +import { NewWorkspaceForm } from "~/components/NewWorkspaceForm"; -import { api } from "~/trpc/react"; +import { api } from "~/utils/api"; export default function MembersPage() { const { openModal, modalContentType } = useModal(); @@ -27,7 +25,7 @@ export default function MembersPage() {