From b086f719c8d0d5d5f0a4e44be5f94ed7126d612b Mon Sep 17 00:00:00 2001 From: Atridad Lahiji <88056492+atridadl@users.noreply.github.com> Date: Thu, 20 Apr 2023 04:20:00 -0600 Subject: [PATCH] Old stuff --- .dockerignore | 6 + .env.example | 24 + .eslintrc.cjs | 4 + .github/workflows/fly.yml | 15 + .gitignore | 6 + .npmrc | 1 + Dockerfile | 49 + README.md | 38 + app/components/Footer.tsx | 33 + app/components/Header.tsx | 59 + app/components/LoadingIndicator.tsx | 9 + app/entry.client.tsx | 18 + app/entry.server.tsx | 137 + app/root.tsx | 61 + app/routes/_index.tsx | 40 + app/routes/api.room.create.tsx | 43 + app/routes/api.room.delete.$roomId.tsx | 42 + app/routes/api.room.get.$roomId.tsx | 66 + app/routes/api.room.get.all.tsx | 44 + app/routes/api.room.presence.get.$roomId.tsx | 82 + app/routes/api.room.set.$roomId.tsx | 87 + app/routes/api.vote.set.$roomId.tsx | 50 + app/routes/api.votes.get.$roomId.tsx | 55 + app/routes/api.webhooks.clerk.ts | 79 + app/routes/dashboard.tsx | 155 + app/routes/room.$roomId.tsx | 456 + app/routes/sign-in.$.tsx | 10 + app/routes/sign-up.$.tsx | 10 + app/services/db.server.ts | 10 + app/services/emitter.server.ts | 18 + app/services/helpers.ts | 47 + app/services/schema.ts | 95 + app/services/types.ts | 71 + app/services/webhookhelpers.server.ts | 44 + app/tailwind.css | 3 + drizzle.config.ts | 13 + fly.toml | 17 + package.json | 49 + pnpm-lock.yaml | 8335 ++++++++++++++++++ public/favicon.ico | Bin 0 -> 15086 bytes public/logo.webp | Bin 0 -> 11680 bytes remix.config.js | 9 + remix.env.d.ts | 2 + tailwind.config.ts | 9 + tsconfig.json | 22 + 45 files changed, 10423 insertions(+) create mode 100644 .dockerignore create mode 100644 .env.example create mode 100644 .eslintrc.cjs create mode 100644 .github/workflows/fly.yml create mode 100644 .gitignore create mode 100644 .npmrc create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 app/components/Footer.tsx create mode 100644 app/components/Header.tsx create mode 100644 app/components/LoadingIndicator.tsx create mode 100644 app/entry.client.tsx create mode 100644 app/entry.server.tsx create mode 100644 app/root.tsx create mode 100644 app/routes/_index.tsx create mode 100644 app/routes/api.room.create.tsx create mode 100644 app/routes/api.room.delete.$roomId.tsx create mode 100644 app/routes/api.room.get.$roomId.tsx create mode 100644 app/routes/api.room.get.all.tsx create mode 100644 app/routes/api.room.presence.get.$roomId.tsx create mode 100644 app/routes/api.room.set.$roomId.tsx create mode 100644 app/routes/api.vote.set.$roomId.tsx create mode 100644 app/routes/api.votes.get.$roomId.tsx create mode 100644 app/routes/api.webhooks.clerk.ts create mode 100644 app/routes/dashboard.tsx create mode 100644 app/routes/room.$roomId.tsx create mode 100644 app/routes/sign-in.$.tsx create mode 100644 app/routes/sign-up.$.tsx create mode 100644 app/services/db.server.ts create mode 100644 app/services/emitter.server.ts create mode 100644 app/services/helpers.ts create mode 100644 app/services/schema.ts create mode 100644 app/services/types.ts create mode 100644 app/services/webhookhelpers.server.ts create mode 100644 app/tailwind.css create mode 100644 drizzle.config.ts create mode 100644 fly.toml create mode 100644 package.json create mode 100644 pnpm-lock.yaml create mode 100644 public/favicon.ico create mode 100644 public/logo.webp create mode 100644 remix.config.js create mode 100644 remix.env.d.ts create mode 100644 tailwind.config.ts create mode 100644 tsconfig.json diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..3f7bf98 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +node_modules + +/.cache +/build +/public/build +.env diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..2dbc567 --- /dev/null +++ b/.env.example @@ -0,0 +1,24 @@ +#Database +DATABASE_URL="" +DATABASE_AUTH_TOKEN="" + +# Redis +REDIS_URL="" +REDIS_EXPIRY_SECONDS="" + +#Auth +NEXT_PUBLIC_CLERK_SIGN_UP_URL="/sign-up" +NEXT_PUBLIC_CLERK_SIGN_IN_URL="/sign-in" +NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="" +CLERK_SECRET_KEY="" +CLERK_WEBHOOK_SIGNING_SECRET="" + +# Ably +ABLY_API_KEY="" + +# Unkey +UNKEY_ROOT_KEY="" + +# Misc +APP_ENV="" +NEXT_PUBLIC_APP_ENV="" diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..2061cd2 --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,4 @@ +/** @type {import('eslint').Linter.Config} */ +module.exports = { + extends: ["@remix-run/eslint-config", "@remix-run/eslint-config/node"], +}; diff --git a/.github/workflows/fly.yml b/.github/workflows/fly.yml new file mode 100644 index 0000000..3a7e876 --- /dev/null +++ b/.github/workflows/fly.yml @@ -0,0 +1,15 @@ +name: Fly Deploy +on: + push: + branches: + - master +jobs: + deploy: + name: Deploy app + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: superfly/flyctl-actions/setup-flyctl@master + - run: flyctl deploy --remote-only + env: + FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3f7bf98 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +node_modules + +/.cache +/build +/public/build +.env diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..f87a044 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +auto-install-peers=true \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..5537664 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,49 @@ +# syntax = docker/dockerfile:1 + +# Adjust NODE_VERSION as desired +ARG NODE_VERSION=18.14.2 +FROM node:${NODE_VERSION}-slim as base + +LABEL fly_launch_runtime="Remix" + +# Remix app lives here +WORKDIR /app + +# Set production environment +ENV NODE_ENV="production" + +# Install pnpm +ARG PNPM_VERSION=8.9.2 +RUN npm install -g pnpm@$PNPM_VERSION + + +# Throw-away build stage to reduce size of final image +FROM base as build + +# Install packages needed to build node modules +RUN apt-get update -qq && \ + apt-get install -y build-essential pkg-config python-is-python3 + +# Install node modules +COPY --link package.json pnpm-lock.yaml ./ +RUN pnpm install --frozen-lockfile --prod=false + +# Copy application code +COPY --link . . + +# Build application +RUN pnpm run build + +# Remove development dependencies +RUN pnpm prune --prod + + +# Final stage for app image +FROM base + +# Copy built application +COPY --from=build /app /app + +# Start the server by default, this can be overwritten at runtime +EXPOSE 3000 +CMD [ "pnpm", "run", "start" ] diff --git a/README.md b/README.md new file mode 100644 index 0000000..da8d02a --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ +# Welcome to Remix! + +- [Remix Docs](https://remix.run/docs) + +## Development + +From your terminal: + +```sh +npm run dev +``` + +This starts your app in development mode, rebuilding assets on file changes. + +## Deployment + +First, build your app for production: + +```sh +npm run build +``` + +Then run the app in production mode: + +```sh +npm start +``` + +Now you'll need to pick a host to deploy it to. + +### DIY + +If you're familiar with deploying node applications, the built-in Remix app server is production-ready. + +Make sure to deploy the output of `remix build` + +- `build/` +- `public/build/` diff --git a/app/components/Footer.tsx b/app/components/Footer.tsx new file mode 100644 index 0000000..fb16572 --- /dev/null +++ b/app/components/Footer.tsx @@ -0,0 +1,33 @@ +import { HeartIcon } from "lucide-react"; +import packagejson from "../../package.json"; + +const Footer = () => { + return ( + + ); +}; + +export default Footer; diff --git a/app/components/Header.tsx b/app/components/Header.tsx new file mode 100644 index 0000000..bd8e46f --- /dev/null +++ b/app/components/Header.tsx @@ -0,0 +1,59 @@ +"use client"; + +import { UserButton, useUser } from "@clerk/remix"; +import { Link, useLocation, useNavigate } from "@remix-run/react"; + +interface NavbarProps { + title: string; +} + +const Navbar = ({ title }: NavbarProps) => { + const { isSignedIn } = useUser(); + const { pathname } = useLocation(); + const navigate = useNavigate(); + + const navigationMenu = () => { + if (pathname !== "/dashboard" && isSignedIn) { + return ( + + Dashboard + + ); + } else if (!isSignedIn) { + return ( + + ); + } + }; + + return ( + + ); +}; + +export default Navbar; diff --git a/app/components/LoadingIndicator.tsx b/app/components/LoadingIndicator.tsx new file mode 100644 index 0000000..7b9b00e --- /dev/null +++ b/app/components/LoadingIndicator.tsx @@ -0,0 +1,9 @@ +const LoadingIndicator = () => { + return ( +
+ +
+ ); +}; + +export default LoadingIndicator; diff --git a/app/entry.client.tsx b/app/entry.client.tsx new file mode 100644 index 0000000..94d5dc0 --- /dev/null +++ b/app/entry.client.tsx @@ -0,0 +1,18 @@ +/** + * By default, Remix will handle hydrating your app on the client for you. + * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨ + * For more information, see https://remix.run/file-conventions/entry.client + */ + +import { RemixBrowser } from "@remix-run/react"; +import { startTransition, StrictMode } from "react"; +import { hydrateRoot } from "react-dom/client"; + +startTransition(() => { + hydrateRoot( + document, + + + + ); +}); diff --git a/app/entry.server.tsx b/app/entry.server.tsx new file mode 100644 index 0000000..0c7712b --- /dev/null +++ b/app/entry.server.tsx @@ -0,0 +1,137 @@ +/** + * By default, Remix will handle generating the HTTP Response for you. + * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨ + * For more information, see https://remix.run/file-conventions/entry.server + */ + +import { PassThrough } from "node:stream"; + +import type { AppLoadContext, EntryContext } from "@remix-run/node"; +import { createReadableStreamFromReadable } from "@remix-run/node"; +import { RemixServer } from "@remix-run/react"; +import isbot from "isbot"; +import { renderToPipeableStream } from "react-dom/server"; + +const ABORT_DELAY = 5_000; + +export default function handleRequest( + request: Request, + responseStatusCode: number, + responseHeaders: Headers, + remixContext: EntryContext, + loadContext: AppLoadContext +) { + return isbot(request.headers.get("user-agent")) + ? handleBotRequest( + request, + responseStatusCode, + responseHeaders, + remixContext + ) + : handleBrowserRequest( + request, + responseStatusCode, + responseHeaders, + remixContext + ); +} + +function handleBotRequest( + request: Request, + responseStatusCode: number, + responseHeaders: Headers, + remixContext: EntryContext +) { + return new Promise((resolve, reject) => { + let shellRendered = false; + const { pipe, abort } = renderToPipeableStream( + , + { + onAllReady() { + shellRendered = true; + const body = new PassThrough(); + const stream = createReadableStreamFromReadable(body); + + responseHeaders.set("Content-Type", "text/html"); + + resolve( + new Response(stream, { + headers: responseHeaders, + status: responseStatusCode, + }) + ); + + pipe(body); + }, + onShellError(error: unknown) { + reject(error); + }, + onError(error: unknown) { + responseStatusCode = 500; + // Log streaming rendering errors from inside the shell. Don't log + // errors encountered during initial shell rendering since they'll + // reject and get logged in handleDocumentRequest. + if (shellRendered) { + console.error(error); + } + }, + } + ); + + setTimeout(abort, ABORT_DELAY); + }); +} + +function handleBrowserRequest( + request: Request, + responseStatusCode: number, + responseHeaders: Headers, + remixContext: EntryContext +) { + return new Promise((resolve, reject) => { + let shellRendered = false; + const { pipe, abort } = renderToPipeableStream( + , + { + onShellReady() { + shellRendered = true; + const body = new PassThrough(); + const stream = createReadableStreamFromReadable(body); + + responseHeaders.set("Content-Type", "text/html"); + + resolve( + new Response(stream, { + headers: responseHeaders, + status: responseStatusCode, + }) + ); + + pipe(body); + }, + onShellError(error: unknown) { + reject(error); + }, + onError(error: unknown) { + responseStatusCode = 500; + // Log streaming rendering errors from inside the shell. Don't log + // errors encountered during initial shell rendering since they'll + // reject and get logged in handleDocumentRequest. + if (shellRendered) { + console.error(error); + } + }, + } + ); + + setTimeout(abort, ABORT_DELAY); + }); +} diff --git a/app/root.tsx b/app/root.tsx new file mode 100644 index 0000000..c1ffd24 --- /dev/null +++ b/app/root.tsx @@ -0,0 +1,61 @@ +import { rootAuthLoader } from "@clerk/remix/ssr.server"; +import { ClerkApp, ClerkErrorBoundary, ClerkLoaded } from "@clerk/remix"; +import type { + LinksFunction, + LoaderFunction, + MetaFunction, +} from "@remix-run/node"; +import { + Links, + LiveReload, + Meta, + Outlet, + Scripts, + ScrollRestoration, +} from "@remix-run/react"; +import stylesheet from "~/tailwind.css"; +import Footer from "./components/Footer"; +import Header from "./components/Header"; + +export const links: LinksFunction = () => [ + { rel: "stylesheet", href: stylesheet }, +]; + +export const meta: MetaFunction = () => { + return [ + { title: "Sprint Padawan" }, + { name: "description", content: "Plan. Sprint. Repeat." }, + ]; +}; + +export const loader: LoaderFunction = (args) => rootAuthLoader(args); + +export const ErrorBoundary = ClerkErrorBoundary(); + +function App() { + return ( + + + + + + + + + +
+
+ +
+