basic settings added
This commit is contained in:
parent
2c66e38698
commit
dba761dcb1
@ -1,17 +1,15 @@
|
|||||||
// This is your Prisma schema file,
|
|
||||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
||||||
|
|
||||||
generator client {
|
generator client {
|
||||||
provider = "prisma-client-js"
|
provider = "prisma-client-js"
|
||||||
}
|
}
|
||||||
|
|
||||||
datasource db {
|
datasource db {
|
||||||
provider = "postgresql"
|
provider = "postgresql"
|
||||||
url = env("DATABASE_URL")
|
url = env("DATABASE_URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
model Example {
|
model User {
|
||||||
id String @id @default(cuid())
|
id String @id @db.Uuid
|
||||||
createdAt DateTime @default(now())
|
email String?
|
||||||
updatedAt DateTime @updatedAt
|
access_token String?
|
||||||
|
created_at DateTime? @default(now()) @db.Timestamptz(6)
|
||||||
}
|
}
|
||||||
|
|||||||
52
src/components/Dashboard/Empty.tsx
Normal file
52
src/components/Dashboard/Empty.tsx
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export default function Empty() {
|
||||||
|
return (
|
||||||
|
<div className="text-center">
|
||||||
|
<svg
|
||||||
|
className="mx-auto h-12 w-12 text-gray-400"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
vectorEffect="non-scaling-stroke"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
d="M9 13h6m-3-3v6m-9 1V7a2 2 0 012-2h6l2 2h6a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<h3 className="mt-2 text-sm font-medium text-gray-900">No Chats Yet</h3>
|
||||||
|
<p className="mt-1 text-sm text-gray-500">
|
||||||
|
Get started by installing the Page Assist Chrome Extension.
|
||||||
|
</p>
|
||||||
|
<div className="mt-6">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="inline-flex items-center rounded-md border border-transparent bg-indigo-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
className="-ml-1 mr-2 h-5 w-5"
|
||||||
|
aria-hidden="true"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<circle cx="12" cy="12" r="10"></circle>
|
||||||
|
<circle cx="12" cy="12" r="4"></circle>
|
||||||
|
<path d="M21.17 8L12 8"></path>
|
||||||
|
<path d="M3.95 6.06L8.54 14"></path>
|
||||||
|
<path d="M10.88 21.94L15.46 14"></path>
|
||||||
|
</svg>
|
||||||
|
Install Extension
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
15
src/components/Dashboard/index.tsx
Normal file
15
src/components/Dashboard/index.tsx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import React from "react";
|
||||||
|
import Empty from "./Empty";
|
||||||
|
|
||||||
|
export default function DashboardBoby() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* align to center of the screen */}
|
||||||
|
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
||||||
|
<div className=" px-4 py-8 sm:px-10">
|
||||||
|
<Empty />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -8,10 +8,12 @@ import {
|
|||||||
} from "@heroicons/react/24/outline";
|
} from "@heroicons/react/24/outline";
|
||||||
import { ChevronDownIcon } from "@heroicons/react/20/solid";
|
import { ChevronDownIcon } from "@heroicons/react/20/solid";
|
||||||
import { useUser } from "@supabase/auth-helpers-react";
|
import { useUser } from "@supabase/auth-helpers-react";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
const navigation = [
|
const navigation = [
|
||||||
{ name: "Home", href: "#", icon: HomeIcon, current: true },
|
{ name: "Home", href: "/dashboard", icon: HomeIcon, current: true },
|
||||||
{ name: "Settings", href: "#", icon: CogIcon, current: false },
|
{ name: "Settings", href: "/dashboard/settings", icon: CogIcon, current: false },
|
||||||
];
|
];
|
||||||
|
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
@ -26,6 +28,7 @@ export default function DashboardLayout({
|
|||||||
}) {
|
}) {
|
||||||
const [sidebarOpen, setSidebarOpen] = useState(false);
|
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||||
const user = useUser();
|
const user = useUser();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -95,20 +98,22 @@ export default function DashboardLayout({
|
|||||||
>
|
>
|
||||||
<div className="space-y-1 px-2">
|
<div className="space-y-1 px-2">
|
||||||
{navigation.map((item) => (
|
{navigation.map((item) => (
|
||||||
<a
|
<Link
|
||||||
key={item.name}
|
key={item.name}
|
||||||
href={item.href}
|
href={item.href}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
item.current
|
router.pathname === item.href
|
||||||
? "bg-gray-100 text-gray-900"
|
? "bg-gray-100 text-gray-900"
|
||||||
: "text-gray-600 hover:bg-gray-50 hover:text-gray-900",
|
: "text-gray-600 hover:bg-gray-50 hover:text-gray-900",
|
||||||
"group flex items-center rounded-md px-2 py-2 text-sm font-medium"
|
"group flex items-center rounded-md px-2 py-2 text-sm font-medium"
|
||||||
)}
|
)}
|
||||||
aria-current={item.current ? "page" : undefined}
|
aria-current={
|
||||||
|
router.pathname === item.href ? "page" : undefined
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<item.icon
|
<item.icon
|
||||||
className={classNames(
|
className={classNames(
|
||||||
item.current
|
router.pathname === item.href
|
||||||
? "text-gray-500"
|
? "text-gray-500"
|
||||||
: "text-gray-400 group-hover:text-gray-500",
|
: "text-gray-400 group-hover:text-gray-500",
|
||||||
"mr-3 h-6 w-6 flex-shrink-0"
|
"mr-3 h-6 w-6 flex-shrink-0"
|
||||||
@ -116,7 +121,7 @@ export default function DashboardLayout({
|
|||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
{item.name}
|
{item.name}
|
||||||
</a>
|
</Link>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
@ -144,16 +149,16 @@ export default function DashboardLayout({
|
|||||||
key={item.name}
|
key={item.name}
|
||||||
href={item.href}
|
href={item.href}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
item.current
|
router.pathname === item.href
|
||||||
? "bg-gray-100 text-gray-900"
|
? "bg-gray-100 text-gray-900"
|
||||||
: "text-gray-600 hover:bg-gray-50 hover:text-gray-900",
|
: "text-gray-600 hover:bg-gray-50 hover:text-gray-900",
|
||||||
"group flex items-center rounded-md px-2 py-2 text-sm font-medium"
|
"group flex items-center rounded-md px-2 py-2 text-sm font-medium"
|
||||||
)}
|
)}
|
||||||
aria-current={item.current ? "page" : undefined}
|
aria-current={router.pathname === item.href ? "page" : undefined}
|
||||||
>
|
>
|
||||||
<item.icon
|
<item.icon
|
||||||
className={classNames(
|
className={classNames(
|
||||||
item.current
|
router.pathname === item.href
|
||||||
? "text-gray-500"
|
? "text-gray-500"
|
||||||
: "text-gray-400 group-hover:text-gray-500",
|
: "text-gray-400 group-hover:text-gray-500",
|
||||||
"mr-3 h-6 w-6 flex-shrink-0"
|
"mr-3 h-6 w-6 flex-shrink-0"
|
||||||
|
|||||||
61
src/components/Settings/index.tsx
Normal file
61
src/components/Settings/index.tsx
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { ClipboardIcon } from "@heroicons/react/24/outline";
|
||||||
|
import { api } from "~/utils/api";
|
||||||
|
|
||||||
|
export default function SettingsBody() {
|
||||||
|
const { data, status } = api.settings.getAccessToken.useQuery();
|
||||||
|
const [isCopied, setIsCopied] = React.useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{status === "loading" && <div>Loading...</div>}
|
||||||
|
{status === "success" && (
|
||||||
|
<div className="divide-ylg:col-span-9">
|
||||||
|
<div className="px-4 py-6 sm:p-6 lg:pb-8">
|
||||||
|
<div>
|
||||||
|
<h2 className="text-lg font-medium leading-6 text-gray-900">
|
||||||
|
Chrom Extension
|
||||||
|
</h2>
|
||||||
|
<p className="mt-1 text-sm text-gray-500">
|
||||||
|
Copy the following code and paste it into the extension.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="mt-6 flex flex-col lg:flex-row">
|
||||||
|
<div className="flex-grow space-y-6">
|
||||||
|
<div className="flex">
|
||||||
|
<div className="flex-grow">
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
readOnly
|
||||||
|
defaultValue={data?.accessToken || ""}
|
||||||
|
className="block w-full rounded-md border-gray-300 shadow-sm focus:border-sky-500 focus:ring-sky-500 sm:text-sm"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span className="ml-3">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
setIsCopied(false);
|
||||||
|
navigator.clipboard.writeText(data?.accessToken || "");
|
||||||
|
setIsCopied(true);
|
||||||
|
}}
|
||||||
|
className="inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-sky-500 focus:ring-offset-2"
|
||||||
|
>
|
||||||
|
<ClipboardIcon
|
||||||
|
className="h-5 w-5 text-gray-500"
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
<span className="ml-2">
|
||||||
|
{isCopied ? "Copied" : "Copy"}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,5 +1,7 @@
|
|||||||
import { createServerSupabaseClient } from "@supabase/auth-helpers-nextjs";
|
import { createServerSupabaseClient } from "@supabase/auth-helpers-nextjs";
|
||||||
import { GetServerSideProps, NextPage } from "next";
|
import { GetServerSideProps, NextPage } from "next";
|
||||||
|
import Head from "next/head";
|
||||||
|
import DashboardBoby from "~/components/Dashboard";
|
||||||
import DashboardLayout from "~/components/Layouts/DashboardLayout";
|
import DashboardLayout from "~/components/Layouts/DashboardLayout";
|
||||||
|
|
||||||
export const getServerSideProps: GetServerSideProps = async (ctx) => {
|
export const getServerSideProps: GetServerSideProps = async (ctx) => {
|
||||||
@ -23,9 +25,14 @@ export const getServerSideProps: GetServerSideProps = async (ctx) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const DashboardPage: NextPage = () => {
|
const DashboardPage: NextPage = () => {
|
||||||
return <DashboardLayout>
|
return (
|
||||||
a
|
<DashboardLayout>
|
||||||
</DashboardLayout>;
|
<Head>
|
||||||
|
<title>Dashboard / PageAssist</title>
|
||||||
|
</Head>
|
||||||
|
<DashboardBoby />
|
||||||
|
</DashboardLayout>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DashboardPage;
|
export default DashboardPage;
|
||||||
|
|||||||
38
src/pages/dashboard/settings.tsx
Normal file
38
src/pages/dashboard/settings.tsx
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { createServerSupabaseClient } from "@supabase/auth-helpers-nextjs";
|
||||||
|
import { GetServerSideProps, NextPage } from "next";
|
||||||
|
import Head from "next/head";
|
||||||
|
import DashboardLayout from "~/components/Layouts/DashboardLayout";
|
||||||
|
import SettingsBody from "~/components/Settings";
|
||||||
|
|
||||||
|
export const getServerSideProps: GetServerSideProps = async (ctx) => {
|
||||||
|
const supabase = createServerSupabaseClient(ctx);
|
||||||
|
const {
|
||||||
|
data: { session },
|
||||||
|
} = await supabase.auth.getSession();
|
||||||
|
|
||||||
|
if (!session) {
|
||||||
|
return {
|
||||||
|
redirect: {
|
||||||
|
destination: "/auth",
|
||||||
|
permanent: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const DashboardSettingsPage: NextPage = () => {
|
||||||
|
return (
|
||||||
|
<DashboardLayout>
|
||||||
|
<Head>
|
||||||
|
<title>Settings / PageAssist</title>
|
||||||
|
</Head>
|
||||||
|
<SettingsBody />
|
||||||
|
</DashboardLayout>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DashboardSettingsPage;
|
||||||
@ -1,5 +1,6 @@
|
|||||||
import { createTRPCRouter } from "~/server/api/trpc";
|
import { createTRPCRouter } from "~/server/api/trpc";
|
||||||
import { exampleRouter } from "~/server/api/routers/example";
|
import { exampleRouter } from "~/server/api/routers/example";
|
||||||
|
import { settingsRouter } from "./routers/settings";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the primary router for your server.
|
* This is the primary router for your server.
|
||||||
@ -8,6 +9,7 @@ import { exampleRouter } from "~/server/api/routers/example";
|
|||||||
*/
|
*/
|
||||||
export const appRouter = createTRPCRouter({
|
export const appRouter = createTRPCRouter({
|
||||||
example: exampleRouter,
|
example: exampleRouter,
|
||||||
|
settings: settingsRouter
|
||||||
});
|
});
|
||||||
|
|
||||||
// export type definition of API
|
// export type definition of API
|
||||||
|
|||||||
35
src/server/api/routers/settings.ts
Normal file
35
src/server/api/routers/settings.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { TRPCError } from "@trpc/server";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { createTRPCRouter, publicProcedure } from "~/server/api/trpc";
|
||||||
|
|
||||||
|
export const settingsRouter = createTRPCRouter({
|
||||||
|
getAccessToken: publicProcedure
|
||||||
|
.query(async ({ ctx }) => {
|
||||||
|
const user = ctx.user;
|
||||||
|
const prisma = ctx.prisma;
|
||||||
|
if (!user) {
|
||||||
|
throw new TRPCError({
|
||||||
|
"code": "UNAUTHORIZED",
|
||||||
|
"message": "You are not authorized to access this resource",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const accessToken = await prisma.user.findFirst({
|
||||||
|
where: {
|
||||||
|
id: user.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!accessToken) {
|
||||||
|
throw new TRPCError({
|
||||||
|
"code": "UNAUTHORIZED",
|
||||||
|
"message": "You are not authorized to access this resource",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
accessToken: accessToken.access_token,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
});
|
||||||
@ -42,8 +42,17 @@ const createInnerTRPCContext = (_opts: CreateContextOptions) => {
|
|||||||
*
|
*
|
||||||
* @see https://trpc.io/docs/context
|
* @see https://trpc.io/docs/context
|
||||||
*/
|
*/
|
||||||
export const createTRPCContext = (_opts: CreateNextContextOptions) => {
|
export const createTRPCContext = async (_opts: CreateNextContextOptions) => {
|
||||||
return createInnerTRPCContext({});
|
const supabaseServerClient = createServerSupabaseClient(_opts);
|
||||||
|
const {
|
||||||
|
data: { user },
|
||||||
|
} = await supabaseServerClient.auth.getUser();
|
||||||
|
|
||||||
|
return {
|
||||||
|
...createInnerTRPCContext({}),
|
||||||
|
user,
|
||||||
|
supabase: supabaseServerClient,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,6 +65,7 @@ export const createTRPCContext = (_opts: CreateNextContextOptions) => {
|
|||||||
import { initTRPC } from "@trpc/server";
|
import { initTRPC } from "@trpc/server";
|
||||||
import superjson from "superjson";
|
import superjson from "superjson";
|
||||||
import { ZodError } from "zod";
|
import { ZodError } from "zod";
|
||||||
|
import { createServerSupabaseClient } from "@supabase/auth-helpers-nextjs";
|
||||||
|
|
||||||
const t = initTRPC.context<typeof createTRPCContext>().create({
|
const t = initTRPC.context<typeof createTRPCContext>().create({
|
||||||
transformer: superjson,
|
transformer: superjson,
|
||||||
@ -64,8 +74,9 @@ const t = initTRPC.context<typeof createTRPCContext>().create({
|
|||||||
...shape,
|
...shape,
|
||||||
data: {
|
data: {
|
||||||
...shape.data,
|
...shape.data,
|
||||||
zodError:
|
zodError: error.cause instanceof ZodError
|
||||||
error.cause instanceof ZodError ? error.cause.flatten() : null,
|
? error.cause.flatten()
|
||||||
|
: null,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user