From cfceb743d6d81a8ad7c72f28fa5bd5d9a690d0a3 Mon Sep 17 00:00:00 2001
From: Ryan Le <31494954+lryanle@users.noreply.github.com>
Date: Fri, 10 Nov 2023 11:15:58 -0600
Subject: [PATCH] WEEE WORKING DEMO
---
.github/workflows/metrics.yml | 2 +-
frontend/app/404.tsx | 19 -
frontend/app/[username].tsx | 80 -
frontend/app/_app.tsx | 17 -
.../authOptions.ts} | 13 +-
frontend/app/api/auth/[...nextauth]/route.ts | 7 +
frontend/app/api/user.ts | 43 -
frontend/app/error.tsx | 40 +
frontend/app/fonts/SF-Pro-Display-Medium.otf | Bin 0 -> 335512 bytes
frontend/app/fonts/index.ts | 13 +
frontend/app/index.tsx | 46 -
frontend/app/layout.tsx | 37 +
frontend/app/{500.tsx => not-found.tsx} | 9 +-
frontend/app/opengraph-image.tsx | 60 +
frontend/app/page.tsx | 129 +
frontend/app/profile.tsx | 24 -
frontend/app/settings.tsx | 40 -
frontend/app/sitemap.ts | 22 +
frontend/components/home/card.tsx | 52 +
frontend/components/home/component-grid.tsx | 56 +
frontend/components/home/demo-modal.tsx | 57 +
frontend/components/home/web-vitals.tsx | 39 +
frontend/components/icons/alert-circle.tsx | 21 -
frontend/components/icons/check-in-circle.tsx | 15 -
frontend/components/icons/check.tsx | 18 -
frontend/components/icons/directory.tsx | 22 -
frontend/components/icons/edit.tsx | 18 -
frontend/components/icons/index.tsx | 12 -
frontend/components/icons/search.tsx | 19 -
frontend/components/icons/upload.tsx | 20 -
frontend/components/icons/x-circle.tsx | 20 -
frontend/components/icons/x.tsx | 19 -
.../layout/cluster-provisioning.tsx | 67 -
.../components/layout/directory-results.tsx | 44 -
frontend/components/layout/directory.tsx | 91 -
frontend/components/layout/footer.tsx | 30 +
frontend/components/layout/index.tsx | 67 -
frontend/components/layout/meta.tsx | 3 +-
frontend/components/layout/nav.tsx | 8 +
frontend/components/layout/navbar.tsx | 105 +-
frontend/components/layout/sidebar.tsx | 110 -
frontend/components/layout/sign-in-modal.tsx | 151 +
frontend/components/layout/toast.tsx | 42 -
frontend/components/layout/user-dropdown.tsx | 65 +
frontend/components/profile/index.tsx | 267 -
.../components/{ => shared}/blur-image.tsx | 0
.../components/shared/counting-numbers.tsx | 41 +
frontend/components/shared/icons/discord.tsx | 15 +
.../{ => shared}/icons/expanding-arrow.tsx | 10 +-
.../components/{ => shared}/icons/github.tsx | 9 +-
frontend/components/shared/icons/google.tsx | 35 +
frontend/components/shared/icons/index.tsx | 11 +
frontend/components/shared/icons/linkedin.tsx | 22 +
.../shared/icons/loading-circle.tsx | 20 +
.../icons/loading-dots.module.css | 0
.../{ => shared}/icons/loading-dots.tsx | 3 +-
.../shared/icons/loading-spinner.module.css | 79 +
.../shared/icons/loading-spinner.tsx | 20 +
.../components/shared/icons/statefarm.tsx | 14 +
frontend/components/shared/icons/twitter.tsx | 14 +
frontend/components/shared/modal.tsx | 64 +
frontend/components/shared/popover.tsx | 60 +
frontend/components/shared/tooltip.tsx | 77 +
frontend/docs/next-steps/commit-convention.md | 6 -
.../docs/next-steps/component-libraries.md | 11 -
frontend/docs/next-steps/deployment.md | 6 -
.../keep-dependencies-up-to-date.md | 4 -
frontend/docs/next-steps/seo.md | 4 -
frontend/docs/next-steps/state-management.md | 7 -
frontend/docs/next-steps/storybook.md | 5 -
frontend/docs/next-steps/testing.md | 9 -
frontend/docs/next-steps/translation.md | 4 -
frontend/docs/next-steps/vscode-extensions.md | 91 -
frontend/docs/steps.md | 156 -
frontend/lib/api/user.ts | 211 -
frontend/lib/constants.ts | 1 +
.../lib/hooks/use-intersection-observer.ts | 19 +-
frontend/lib/hooks/use-local-storage.ts | 26 +
frontend/lib/hooks/use-media-query.ts | 46 +
frontend/lib/hooks/use-scroll.ts | 16 +
frontend/lib/prisma.ts | 11 +
frontend/lib/utils.ts | 71 +-
frontend/next.config.js | 4 +
frontend/package-lock.json | 16084 +++++++++-------
frontend/package.json | 12 +-
frontend/prisma/schema.prisma | 61 +
frontend/tailwind.config.js | 1 +
frontend/tsconfig.json | 4 +
88 files changed, 10884 insertions(+), 8519 deletions(-)
delete mode 100644 frontend/app/404.tsx
delete mode 100644 frontend/app/[username].tsx
delete mode 100644 frontend/app/_app.tsx
rename frontend/app/api/auth/{[...nextauth].ts => [...nextauth]/authOptions.ts} (94%)
create mode 100644 frontend/app/api/auth/[...nextauth]/route.ts
delete mode 100644 frontend/app/api/user.ts
create mode 100644 frontend/app/error.tsx
create mode 100644 frontend/app/fonts/SF-Pro-Display-Medium.otf
create mode 100644 frontend/app/fonts/index.ts
delete mode 100644 frontend/app/index.tsx
create mode 100644 frontend/app/layout.tsx
rename frontend/app/{500.tsx => not-found.tsx} (63%)
create mode 100644 frontend/app/opengraph-image.tsx
create mode 100644 frontend/app/page.tsx
delete mode 100644 frontend/app/profile.tsx
delete mode 100644 frontend/app/settings.tsx
create mode 100644 frontend/app/sitemap.ts
create mode 100644 frontend/components/home/card.tsx
create mode 100644 frontend/components/home/component-grid.tsx
create mode 100644 frontend/components/home/demo-modal.tsx
create mode 100644 frontend/components/home/web-vitals.tsx
delete mode 100644 frontend/components/icons/alert-circle.tsx
delete mode 100644 frontend/components/icons/check-in-circle.tsx
delete mode 100644 frontend/components/icons/check.tsx
delete mode 100644 frontend/components/icons/directory.tsx
delete mode 100644 frontend/components/icons/edit.tsx
delete mode 100644 frontend/components/icons/index.tsx
delete mode 100644 frontend/components/icons/search.tsx
delete mode 100644 frontend/components/icons/upload.tsx
delete mode 100644 frontend/components/icons/x-circle.tsx
delete mode 100644 frontend/components/icons/x.tsx
delete mode 100644 frontend/components/layout/cluster-provisioning.tsx
delete mode 100644 frontend/components/layout/directory-results.tsx
delete mode 100644 frontend/components/layout/directory.tsx
create mode 100644 frontend/components/layout/footer.tsx
delete mode 100644 frontend/components/layout/index.tsx
create mode 100644 frontend/components/layout/nav.tsx
delete mode 100644 frontend/components/layout/sidebar.tsx
create mode 100644 frontend/components/layout/sign-in-modal.tsx
delete mode 100644 frontend/components/layout/toast.tsx
create mode 100644 frontend/components/layout/user-dropdown.tsx
delete mode 100644 frontend/components/profile/index.tsx
rename frontend/components/{ => shared}/blur-image.tsx (100%)
create mode 100644 frontend/components/shared/counting-numbers.tsx
create mode 100644 frontend/components/shared/icons/discord.tsx
rename frontend/components/{ => shared}/icons/expanding-arrow.tsx (74%)
rename frontend/components/{ => shared}/icons/github.tsx (85%)
create mode 100644 frontend/components/shared/icons/google.tsx
create mode 100644 frontend/components/shared/icons/index.tsx
create mode 100644 frontend/components/shared/icons/linkedin.tsx
create mode 100644 frontend/components/shared/icons/loading-circle.tsx
rename frontend/components/{ => shared}/icons/loading-dots.module.css (100%)
rename frontend/components/{ => shared}/icons/loading-dots.tsx (76%)
create mode 100644 frontend/components/shared/icons/loading-spinner.module.css
create mode 100644 frontend/components/shared/icons/loading-spinner.tsx
create mode 100644 frontend/components/shared/icons/statefarm.tsx
create mode 100644 frontend/components/shared/icons/twitter.tsx
create mode 100644 frontend/components/shared/modal.tsx
create mode 100644 frontend/components/shared/popover.tsx
create mode 100644 frontend/components/shared/tooltip.tsx
delete mode 100644 frontend/docs/next-steps/commit-convention.md
delete mode 100644 frontend/docs/next-steps/component-libraries.md
delete mode 100644 frontend/docs/next-steps/deployment.md
delete mode 100644 frontend/docs/next-steps/keep-dependencies-up-to-date.md
delete mode 100644 frontend/docs/next-steps/seo.md
delete mode 100644 frontend/docs/next-steps/state-management.md
delete mode 100644 frontend/docs/next-steps/storybook.md
delete mode 100644 frontend/docs/next-steps/testing.md
delete mode 100644 frontend/docs/next-steps/translation.md
delete mode 100644 frontend/docs/next-steps/vscode-extensions.md
delete mode 100644 frontend/docs/steps.md
delete mode 100644 frontend/lib/api/user.ts
create mode 100644 frontend/lib/hooks/use-local-storage.ts
create mode 100644 frontend/lib/hooks/use-media-query.ts
create mode 100644 frontend/lib/hooks/use-scroll.ts
create mode 100644 frontend/lib/prisma.ts
create mode 100644 frontend/prisma/schema.prisma
diff --git a/.github/workflows/metrics.yml b/.github/workflows/metrics.yml
index 6c12ea3..399f28f 100644
--- a/.github/workflows/metrics.yml
+++ b/.github/workflows/metrics.yml
@@ -1,7 +1,7 @@
name: Metrics
on:
# Schedule daily updates
- schedule: [{cron: "0 0 * * *"}]
+ # schedule: [{cron: "0 0 * * *"}]
# (optional) Run workflow manually
workflow_dispatch:
# (optional) Run workflow when pushing on master/main
diff --git a/frontend/app/404.tsx b/frontend/app/404.tsx
deleted file mode 100644
index d9fe7ea..0000000
--- a/frontend/app/404.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import Meta, { defaultMetaProps } from "@/components/layout/meta";
-export { getStaticProps } from ".";
-
-export default function Custom404() {
- return (
-
-
-
- 404 | User Not Found
-
-
- );
-}
diff --git a/frontend/app/[username].tsx b/frontend/app/[username].tsx
deleted file mode 100644
index 9e4c61d..0000000
--- a/frontend/app/[username].tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-import { ParsedUrlQuery } from "querystring";
-import { GetStaticProps } from "next";
-import { defaultMetaProps } from "@/components/layout/meta";
-import { getUser, getAllUsers, getUserCount } from "@/lib/api/user";
-export { default } from ".";
-import clientPromise from "@/lib/mongodb";
-
-interface Params extends ParsedUrlQuery {
- username: string;
-}
-
-export const getStaticPaths = async () => {
- // You should remove this try-catch block once your MongoDB Cluster is fully provisioned
- try {
- await clientPromise;
- } catch (e: any) {
- // cluster is still provisioning
- return {
- paths: [],
- fallback: true,
- };
- }
-
- const results = await getAllUsers();
- const paths = results.flatMap(({ users }) =>
- users.map((user) => ({ params: { username: user.username } }))
- );
- return {
- paths,
- fallback: true,
- };
-};
-
-export const getStaticProps: GetStaticProps = async (context) => {
- // You should remove this try-catch block once your MongoDB Cluster is fully provisioned
- try {
- await clientPromise;
- } catch (e: any) {
- if (e.code === "ENOTFOUND") {
- // cluster is still provisioning
- return {
- props: {
- clusterStillProvisioning: true,
- },
- };
- } else {
- throw new Error(`Connection limit reached. Please try again later.`);
- }
- }
-
- const { username } = context.params as Params;
- const user = await getUser(username);
- if (!user) {
- return {
- notFound: true,
- revalidate: 10,
- };
- }
-
- const results = await getAllUsers();
- const totalUsers = await getUserCount();
-
- const ogUrl = `https://mongodb.vercel.app/${user.username}`;
- const meta = {
- ...defaultMetaProps,
- title: `${user.name}'s Profile | MongoDB Starter Kit`,
- ogImage: `https://api.microlink.io/?url=${ogUrl}&screenshot=true&meta=false&embed=screenshot.url`,
- ogUrl: `https://mongodb.vercel.app/${user.username}`,
- };
-
- return {
- props: {
- meta,
- results,
- totalUsers,
- user,
- },
- revalidate: 10,
- };
-};
diff --git a/frontend/app/_app.tsx b/frontend/app/_app.tsx
deleted file mode 100644
index 4680ad0..0000000
--- a/frontend/app/_app.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import Layout from "@/components/layout";
-import "@/styles/globals.css";
-import { SessionProvider } from "next-auth/react";
-import { AppProps } from "next/app";
-
-export default function MyApp({
- Component,
- pageProps: { session, ...pageProps },
-}: AppProps) {
- return (
-
-
-
-
-
- );
-}
diff --git a/frontend/app/api/auth/[...nextauth].ts b/frontend/app/api/auth/[...nextauth]/authOptions.ts
similarity index 94%
rename from frontend/app/api/auth/[...nextauth].ts
rename to frontend/app/api/auth/[...nextauth]/authOptions.ts
index b0187dc..85c1d0c 100644
--- a/frontend/app/api/auth/[...nextauth].ts
+++ b/frontend/app/api/auth/[...nextauth]/authOptions.ts
@@ -1,14 +1,14 @@
/* eslint-disable new-cap */
-import clientPromise from "@/lib/mongodb";
-import { MongoDBAdapter } from "@auth/mongodb-adapter";
-import NextAuth, { NextAuthOptions } from "next-auth";
+import prisma from "@/lib/prisma";
+import { PrismaAdapter } from "@next-auth/prisma-adapter";
+import { NextAuthOptions } from "next-auth";
import DiscordProvider from "next-auth/providers/discord";
import GitHubProvider from "next-auth/providers/github";
import GoogleProvider from "next-auth/providers/google";
import LinkedInProvider from "next-auth/providers/linkedin";
export const authOptions: NextAuthOptions = {
- adapter: MongoDBAdapter(clientPromise),
+ adapter: PrismaAdapter(prisma),
providers: [
GitHubProvider({
clientId: process.env.GITHUB_CLIENT_ID as string,
@@ -142,7 +142,4 @@ export const authOptions: NextAuthOptions = {
return session;
},
},
-};
-
-const handler = NextAuth(authOptions);
-export default handler;
+};
\ No newline at end of file
diff --git a/frontend/app/api/auth/[...nextauth]/route.ts b/frontend/app/api/auth/[...nextauth]/route.ts
new file mode 100644
index 0000000..966a375
--- /dev/null
+++ b/frontend/app/api/auth/[...nextauth]/route.ts
@@ -0,0 +1,7 @@
+/* eslint-disable new-cap */
+import NextAuth from "next-auth";
+import { authOptions } from "./authOptions";
+
+const handler = NextAuth(authOptions);
+export { handler as GET, handler as POST };
+
diff --git a/frontend/app/api/user.ts b/frontend/app/api/user.ts
deleted file mode 100644
index c8b1c14..0000000
--- a/frontend/app/api/user.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import { getMdxSource, searchUser, updateUser } from "@/lib/api/user";
-import type { NextApiRequest, NextApiResponse } from "next";
-import { getSession } from "next-auth/react";
-
-export default async function handler(
- req: NextApiRequest,
- res: NextApiResponse
-) {
- if (req.method === "GET") {
- try {
- const result = await searchUser(req.query.query as string);
- return res.status(200).json(result);
- } catch (e: any) {
- console.log(e);
- return res.status(500).json({
- error: e.toString(),
- });
- }
- } else if (req.method === "PUT") {
- const { username, bio } = req.body;
- const session = await getSession({ req });
- if (!session || session.user?.name !== username) {
- return res.status(401).json({
- error: "Unauthorized",
- });
- }
- try {
- const result = await updateUser(username, bio);
- if (result) {
- await res.revalidate(`/${username}`);
- }
- const bioMdx = await getMdxSource(bio); // return bioMdx to optimistically show updated state
- return res.status(200).json(bioMdx);
- } catch (e: any) {
- console.log(e);
- return res.status(500).json({
- error: e.toString(),
- });
- }
- } else {
- return res.status(405).end(`Method ${req.method} Not Allowed`);
- }
-}
diff --git a/frontend/app/error.tsx b/frontend/app/error.tsx
new file mode 100644
index 0000000..dcb5f93
--- /dev/null
+++ b/frontend/app/error.tsx
@@ -0,0 +1,40 @@
+'use client' // Error components must be Client Components
+
+import Meta, { defaultMetaProps } from "@/components/layout/meta";
+import { useEffect } from "react";
+
+export default function Error({
+ error,
+ reset,
+}: {
+ error: Error & { digest?: string };
+ reset: () => void;
+}) {
+ useEffect(() => {
+ // Log the error to an error reporting service
+ console.error(error);
+ }, [error]);
+
+ return (
+
+
+
+ 404 | User Not Found
+
+
+
+ );
+}
diff --git a/frontend/app/fonts/SF-Pro-Display-Medium.otf b/frontend/app/fonts/SF-Pro-Display-Medium.otf
new file mode 100644
index 0000000000000000000000000000000000000000..b2f7daca100957c47773fb6655226f57162811c7
GIT binary patch
literal 335512
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