From 95feb9f01a7d09676c96219b008d7e3e1785c2e5 Mon Sep 17 00:00:00 2001 From: Luke Vella Date: Mon, 6 Nov 2023 09:15:49 +0000 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Switch=20to=20app=20router?= =?UTF-8?q?=20(#922)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.development | 11 + .eslintrc.json | 25 - .github/workflows/ci.yml | 16 +- README.md | 62 +- apps/docs/.eslintrc.js | 4 + apps/docs/package.json | 5 +- apps/docs/tsconfig.json | 5 + apps/landing/.eslintrc.js | 4 + apps/landing/package.json | 8 - apps/landing/src/components/error-page.tsx | 2 +- apps/landing/src/components/home/bonus.tsx | 6 +- .../landing/src/components/home/color-hash.ts | 2 +- apps/landing/src/components/home/hero.tsx | 2 +- .../src/components/layouts/blog-layout.tsx | 2 +- .../src/components/layouts/page-layout.tsx | 2 +- .../components/layouts/page-layout/footer.tsx | 14 +- apps/landing/src/components/marketing.tsx | 2 +- apps/landing/src/pages/404.tsx | 2 +- apps/landing/src/pages/api/og-image.tsx | 2 +- apps/landing/src/pages/blog/[slug].tsx | 4 +- apps/landing/src/pages/pricing.tsx | 2 +- apps/landing/tsconfig.json | 19 +- .env.test => apps/web/.env.test | 4 +- apps/web/.eslintrc.js | 4 + apps/web/declarations/i18next.d.ts | 2 +- apps/web/next-env.d.ts | 1 + apps/web/next.config.js | 10 +- apps/web/package.json | 18 +- apps/web/playwright.config.ts | 10 +- apps/web/postcss.config.js | 5 +- apps/web/public/locales/en/app.json | 3 +- apps/web/src/app/[locale]/(admin)/layout.tsx | 6 + .../web/src/app/[locale]/(admin)/new/page.tsx | 17 + .../(admin)/poll/[urlId]/duplicate/page.tsx} | 18 +- .../poll/[urlId]/edit-details/page.tsx} | 16 +- .../poll/[urlId]/edit-options/page.tsx} | 19 +- .../poll/[urlId]/edit-settings/page.tsx} | 19 +- .../(admin)/poll/[urlId]/finalize/page.tsx} | 16 +- .../[locale]/(admin)/poll/[urlId]/layout.tsx | 31 + .../[locale]/(admin)/poll/[urlId]/page.tsx} | 25 +- .../src/app/[locale]/(admin)/polls/page.tsx | 18 + .../[locale]/(admin)/polls/polls-page.tsx} | 28 +- .../settings/billing/billing-page.tsx} | 134 +- .../(admin)/settings/billing/page.tsx | 14 + .../app/[locale]/(admin)/settings/layout.tsx | 10 + .../(admin)/settings/preferences/page.tsx | 14 + .../preferences/preferences-page.tsx} | 17 +- .../(admin)/settings/profile/page.tsx | 14 + .../settings/profile/profile-page.tsx} | 14 +- apps/web/src/app/[locale]/(auth)/layout.tsx | 7 + .../src/app/[locale]/(auth)/login/page.tsx | 14 + .../src/app/[locale]/(auth)/register/page.tsx | 14 + .../(auth)/register/register-page.tsx} | 37 +- .../app/[locale]/admin/[adminUrlId]/page.tsx | 27 + .../app/[locale]/admin/[adminUrlId]/types.ts | 5 + .../[locale]/auth/login/login-page.tsx} | 65 +- .../src/app/[locale]/auth/login/not-found.tsx | 33 + apps/web/src/app/[locale]/auth/login/page.tsx | 56 + .../app/[locale]/invite/[urlId]/layout.tsx | 93 + .../src/app/[locale]/invite/[urlId]/page.tsx | 114 + apps/web/src/app/[locale]/layout.tsx | 33 + apps/web/src/app/[locale]/logout/page.tsx | 10 + apps/web/src/app/[locale]/not-found.tsx | 39 + .../[locale]/p/[participantUrlId]/page.tsx | 27 + .../[locale]/p/[participantUrlId]/types.ts | 5 + apps/web/src/app/[locale]/types.ts | 3 + apps/web/src/app/components/redirect.tsx | 32 + apps/web/src/app/i18n.ts | 30 + apps/web/src/app/i18n/client.tsx | 52 + apps/web/src/app/i18n/settings.ts | 21 + apps/web/src/app/providers.tsx | 46 + apps/web/src/components/auth/auth-forms.tsx | 5 +- .../src/components/billing/billing-plans.tsx | 2 +- apps/web/src/components/clock.tsx | 2 +- apps/web/src/components/create-poll.tsx | 3 +- .../src/components/discussion/discussion.tsx | 6 +- apps/web/src/components/error-page.tsx | 6 +- apps/web/src/components/event-card.tsx | 2 +- apps/web/src/components/featurebase.tsx | 2 +- apps/web/src/components/feedback.tsx | 14 +- .../date-navigation-toolbar.tsx | 2 +- .../month-calendar/month-calendar.tsx | 18 +- .../month-calendar/time-picker.tsx | 2 +- .../poll-options-form/poll-options-form.tsx | 2 +- .../forms/poll-options-form/week-calendar.tsx | 4 +- .../src/components/forms/poll-settings.tsx | 14 +- apps/web/src/components/invite-dialog.tsx | 2 +- .../src/components/layouts/admin-layout.tsx | 29 - .../src/components/layouts/auth-layout.tsx | 16 - .../src/components/layouts/poll-layout.tsx | 40 +- .../src/components/layouts/profile-layout.tsx | 32 +- .../components/layouts/standard-layout.tsx | 30 +- apps/web/src/components/login-link.tsx | 5 +- apps/web/src/components/modal/modal.tsx | 2 +- .../src/components/participant-dropdown.tsx | 2 +- apps/web/src/components/pay-wall.tsx | 18 +- apps/web/src/components/poll-context.tsx | 2 +- apps/web/src/components/poll-status.tsx | 2 +- apps/web/src/components/poll/desktop-poll.tsx | 8 +- .../poll/desktop-poll/participant-row.tsx | 2 +- apps/web/src/components/poll/manage-poll.tsx | 22 +- .../poll/manage-poll/delete-poll-dialog.tsx | 2 +- apps/web/src/components/poll/mobile-poll.tsx | 2 +- .../poll/mobile-poll/poll-option.tsx | 2 +- .../poll/mobile-poll/time-slot-option.tsx | 2 +- .../components/poll/notifications-toggle.tsx | 2 +- .../web/src/components/poll/score-summary.tsx | 6 +- apps/web/src/components/pro-badge.tsx | 19 +- apps/web/src/components/register-link.tsx | 7 +- .../settings/language-preference.tsx | 6 +- apps/web/src/components/settings/settings.tsx | 2 +- apps/web/src/components/spinner.tsx | 2 +- .../time-zone-picker/time-zone-picker.tsx | 2 +- .../time-zone-picker/time-zone-select.tsx | 2 +- apps/web/src/components/trans.tsx | 4 +- apps/web/src/components/user-dropdown.tsx | 26 +- apps/web/src/components/user-provider.tsx | 3 +- apps/web/src/components/user.tsx | 2 +- apps/web/src/contexts/locale.tsx | 16 - apps/web/src/contexts/plan.tsx | 1 + apps/web/src/contexts/poll.tsx | 6 +- apps/web/src/contexts/role.tsx | 6 +- apps/web/src/pages/404.tsx | 2 +- .../auth/disable-notifications.tsx | 0 .../src/pages/{ => [locale]}/auth/error.tsx | 2 +- apps/web/src/pages/_app.tsx | 29 +- apps/web/src/pages/admin/[urlId].tsx | 39 - apps/web/src/pages/api/og-image-poll.tsx | 2 +- apps/web/src/pages/invite/[urlId].tsx | 221 -- apps/web/src/pages/login.tsx | 32 - apps/web/src/pages/logout.tsx | 18 - apps/web/src/pages/new.tsx | 103 - apps/web/src/pages/p/[urlId].tsx | 39 - apps/web/src/types.ts | 4 +- apps/web/src/utils/constants.ts | 2 +- apps/web/src/utils/dayjs.tsx | 6 +- apps/web/src/utils/trpc/client.ts | 33 +- apps/web/src/utils/trpc/config.ts | 31 + apps/web/tsconfig.json | 28 +- docker-compose.yml | 6 +- package.json | 26 +- packages/backend/.eslintrc.js | 4 + packages/backend/package.json | 3 +- packages/backend/trpc/routers/polls.ts | 5 +- packages/backend/tsconfig.json | 5 +- packages/backend/utils/date.ts | 7 +- packages/components/index.ts | 2 - packages/components/package.json | 10 - packages/components/tsconfig.json | 24 - packages/database/.eslintrc.js | 4 + packages/database/package.json | 4 +- packages/database/prisma/seed.ts | 11 +- packages/database/tsconfig.json | 5 + packages/emails/.eslintrc.js | 4 + packages/emails/src/index.ts | 3 +- packages/emails/src/send-email.tsx | 28 +- .../src/templates/components/email-layout.tsx | 2 +- packages/emails/tsconfig.json | 4 +- packages/eslint-config/package.json | 18 + packages/eslint-config/preset.js | 37 + packages/icons/.eslintrc.js | 4 + packages/icons/src/index.ts | 1 - packages/icons/tsconfig.json | 4 +- packages/languages/tsconfig.json | 2 +- packages/tailwind-config/tailwind.config.js | 7 +- packages/tsconfig/base.json | 23 +- packages/tsconfig/environment.d.ts | 95 - packages/tsconfig/next.json | 14 +- packages/tsconfig/package.json | 6 +- packages/tsconfig/react-library.json | 12 - packages/tsconfig/react.json | 9 + packages/ui/billing-plan.tsx | 2 +- packages/ui/button.tsx | 1 + packages/ui/checkbox.tsx | 2 +- packages/ui/command.tsx | 2 +- packages/ui/dialog.tsx | 2 +- packages/ui/dropdown-menu.tsx | 2 +- packages/ui/radio-group.tsx | 2 +- packages/ui/select.tsx | 2 +- turbo.json | 16 +- yarn.lock | 2123 ++++++++--------- 181 files changed, 2507 insertions(+), 2494 deletions(-) create mode 100644 .env.development delete mode 100644 .eslintrc.json create mode 100644 apps/docs/.eslintrc.js create mode 100644 apps/docs/tsconfig.json create mode 100644 apps/landing/.eslintrc.js rename .env.test => apps/web/.env.test (59%) create mode 100644 apps/web/.eslintrc.js create mode 100644 apps/web/src/app/[locale]/(admin)/layout.tsx create mode 100644 apps/web/src/app/[locale]/(admin)/new/page.tsx rename apps/web/src/{pages/poll/[urlId]/duplicate.tsx => app/[locale]/(admin)/poll/[urlId]/duplicate/page.tsx} (89%) rename apps/web/src/{pages/poll/[urlId]/edit-details.tsx => app/[locale]/(admin)/poll/[urlId]/edit-details/page.tsx} (86%) rename apps/web/src/{pages/poll/[urlId]/edit-options.tsx => app/[locale]/(admin)/poll/[urlId]/edit-options/page.tsx} (88%) rename apps/web/src/{pages/poll/[urlId]/edit-settings.tsx => app/[locale]/(admin)/poll/[urlId]/edit-settings/page.tsx} (79%) rename apps/web/src/{pages/poll/[urlId]/finalize.tsx => app/[locale]/(admin)/poll/[urlId]/finalize/page.tsx} (86%) create mode 100644 apps/web/src/app/[locale]/(admin)/poll/[urlId]/layout.tsx rename apps/web/src/{pages/poll/[urlId].tsx => app/[locale]/(admin)/poll/[urlId]/page.tsx} (72%) create mode 100644 apps/web/src/app/[locale]/(admin)/polls/page.tsx rename apps/web/src/{pages/polls.tsx => app/[locale]/(admin)/polls/polls-page.tsx} (91%) rename apps/web/src/{pages/settings/billing.tsx => app/[locale]/(admin)/settings/billing/billing-page.tsx} (69%) create mode 100644 apps/web/src/app/[locale]/(admin)/settings/billing/page.tsx create mode 100644 apps/web/src/app/[locale]/(admin)/settings/layout.tsx create mode 100644 apps/web/src/app/[locale]/(admin)/settings/preferences/page.tsx rename apps/web/src/{pages/settings/preferences.tsx => app/[locale]/(admin)/settings/preferences/preferences-page.tsx} (76%) create mode 100644 apps/web/src/app/[locale]/(admin)/settings/profile/page.tsx rename apps/web/src/{pages/settings/profile.tsx => app/[locale]/(admin)/settings/profile/profile-page.tsx} (83%) create mode 100644 apps/web/src/app/[locale]/(auth)/layout.tsx create mode 100644 apps/web/src/app/[locale]/(auth)/login/page.tsx create mode 100644 apps/web/src/app/[locale]/(auth)/register/page.tsx rename apps/web/src/{pages/register.tsx => app/[locale]/(auth)/register/register-page.tsx} (85%) create mode 100644 apps/web/src/app/[locale]/admin/[adminUrlId]/page.tsx create mode 100644 apps/web/src/app/[locale]/admin/[adminUrlId]/types.ts rename apps/web/src/{pages/auth/login.tsx => app/[locale]/auth/login/login-page.tsx} (65%) create mode 100644 apps/web/src/app/[locale]/auth/login/not-found.tsx create mode 100644 apps/web/src/app/[locale]/auth/login/page.tsx create mode 100644 apps/web/src/app/[locale]/invite/[urlId]/layout.tsx create mode 100644 apps/web/src/app/[locale]/invite/[urlId]/page.tsx create mode 100644 apps/web/src/app/[locale]/layout.tsx create mode 100644 apps/web/src/app/[locale]/logout/page.tsx create mode 100644 apps/web/src/app/[locale]/not-found.tsx create mode 100644 apps/web/src/app/[locale]/p/[participantUrlId]/page.tsx create mode 100644 apps/web/src/app/[locale]/p/[participantUrlId]/types.ts create mode 100644 apps/web/src/app/[locale]/types.ts create mode 100644 apps/web/src/app/components/redirect.tsx create mode 100644 apps/web/src/app/i18n.ts create mode 100644 apps/web/src/app/i18n/client.tsx create mode 100644 apps/web/src/app/i18n/settings.ts create mode 100644 apps/web/src/app/providers.tsx delete mode 100644 apps/web/src/components/layouts/admin-layout.tsx delete mode 100644 apps/web/src/components/layouts/auth-layout.tsx delete mode 100644 apps/web/src/contexts/locale.tsx rename apps/web/src/pages/{ => [locale]}/auth/disable-notifications.tsx (100%) rename apps/web/src/pages/{ => [locale]}/auth/error.tsx (96%) delete mode 100644 apps/web/src/pages/admin/[urlId].tsx delete mode 100644 apps/web/src/pages/invite/[urlId].tsx delete mode 100644 apps/web/src/pages/login.tsx delete mode 100644 apps/web/src/pages/logout.tsx delete mode 100644 apps/web/src/pages/new.tsx delete mode 100644 apps/web/src/pages/p/[urlId].tsx create mode 100644 apps/web/src/utils/trpc/config.ts create mode 100644 packages/backend/.eslintrc.js delete mode 100644 packages/components/index.ts delete mode 100644 packages/components/package.json delete mode 100644 packages/components/tsconfig.json create mode 100644 packages/database/.eslintrc.js create mode 100644 packages/database/tsconfig.json create mode 100644 packages/emails/.eslintrc.js create mode 100644 packages/eslint-config/package.json create mode 100644 packages/eslint-config/preset.js create mode 100644 packages/icons/.eslintrc.js delete mode 100644 packages/tsconfig/environment.d.ts delete mode 100644 packages/tsconfig/react-library.json create mode 100644 packages/tsconfig/react.json diff --git a/.env.development b/.env.development new file mode 100644 index 000000000..c0451365a --- /dev/null +++ b/.env.development @@ -0,0 +1,11 @@ +# A random 32-character secret key used to encrypt user sessions +SECRET_PASSWORD=abcdef1234567890abcdef1234567890 +# The base url where this instance is accessible, including the scheme. +# Example: https://example.com +NEXT_PUBLIC_BASE_URL=http://localhost:3000 +NEXTAUTH_URL=$NEXT_PUBLIC_BASE_URL +# A connection string to your Postgres database +DATABASE_URL="postgres://postgres:postgres@localhost:5450/db" + +# Suppress warning from sentry during local development +SENTRY_IGNORE_API_RESOLUTION_ERROR=1 \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 20647c2ab..000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "extends": ["next/core-web-vitals", "turbo"], - "plugins": ["simple-import-sort", "@typescript-eslint"], - "ignorePatterns": ["**/playwright-report/*.js"], - "overrides": [ - { - "files": ["**/*.ts", "**/*.tsx"], - "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint"], - "extends": ["plugin:@typescript-eslint/recommended"], - "rules": { - "@typescript-eslint/no-unused-vars": "error" - } - } - ], - "rules": { - "simple-import-sort/imports": "error", - "simple-import-sort/exports": "error", - "import/first": "error", - "import/newline-after-import": "error", - "import/no-duplicates": "error", - "no-console": ["error", { "allow": ["warn", "error", "info"] }], - "no-unused-vars": "error" - } -} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a7dca149..ad8a66ef4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,7 +40,7 @@ jobs: runs-on: ubuntu-latest env: TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} - TURBO_TEAM: ${{ secrets.TURBO_TEAM }} + TURBO_TEAM: ${{ vars.TURBO_TEAM }} steps: # Downloads a copy of the code in your repository before running CI tests - name: Check out repository code @@ -56,21 +56,21 @@ jobs: node-version: 18 cache: yarn - - name: Set environment variables - run: | - echo "DATABASE_URL=postgresql://postgres:password@localhost:5432/rallly" >> $GITHUB_ENV - - name: Install dependencies run: yarn install --frozen-lockfile + - name: Set environment variables + run: | + echo "DATABASE_URL=postgresql://postgres:password@localhost:5450/db" >> $GITHUB_ENV + - name: Run db run: | docker pull postgres:14.2 - docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=password -e POSTGRES_DB=rallly postgres:14.2 - yarn wait-on --timeout 60000 tcp:localhost:5432 + docker run -d -p 5450:5432 -e POSTGRES_PASSWORD=password -e POSTGRES_DB=rallly postgres:14.2 + yarn wait-on --timeout 60000 tcp:localhost:5450 - name: Deploy migrations - run: yarn db:deploy + run: yarn db:setup - name: Install playwright dependencies run: yarn playwright install --with-deps chromium diff --git a/README.md b/README.md index 92817a6b9..958315c1a 100644 --- a/README.md +++ b/README.md @@ -24,45 +24,53 @@ Built with [Next.js](https://github.com/vercel/next.js/), [Prisma](https://githu Check out the [self-hosting docs](https://support.rallly.co/self-hosting) for more information on running your own instance of Rallly. -## Development +## Get started -Clone this repo and change directory to the root of the repository. +1. Clone the repository switch to the project directory -```bash -git clone https://github.com/lukevella/rallly.git -cd rallly -``` + ```bash + git clone https://github.com/lukevella/rallly.git + cd rallly + ``` -Install dependencies +2. Install dependencies -``` -yarn -``` + ``` + yarn + ``` -Copy the sample `.env` file then open it and set the required [configuration options](https://support.rallly.co/self-hosting/configuration-options). +3. Setup environment variables -```bash -cp sample.env .env -``` + ```bash + cp sample.env .env + ``` -Next, run the following command: + Create a `.env` file by copying `sample.env` then open it and set the required [configuration options](https://support.rallly.co/self-hosting/configuration-options). -``` -yarn db:generate && yarn db:reset -``` +4. Setup the database -This will: + If you don't have a postgres database running locally, you can spin up a new database using docker by running: -- generate the prisma database client -- run migrations to create the database schema -- seed the database with some random data + ``` + yarn dx + ``` -Start the Next.js server + If you already have a postgres database, you can run the migrations and seed the database by running: -``` -# For development -yarn dev -``` + ``` + yarn db:setup + ``` + + This will: + + - run migrations to create the database schema + - seed the database with test users and random data + +5. Start the Next.js server + + ``` + yarn dev + ``` ## Contributors diff --git a/apps/docs/.eslintrc.js b/apps/docs/.eslintrc.js new file mode 100644 index 000000000..3d9be6e61 --- /dev/null +++ b/apps/docs/.eslintrc.js @@ -0,0 +1,4 @@ +/** @type {import("eslint").Linter.Config} */ +module.exports = { + ...require("@rallly/eslint-config")(__dirname), +}; diff --git a/apps/docs/package.json b/apps/docs/package.json index 2f0cdf097..49e3d38ab 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -1,5 +1,8 @@ { "name": "@rallly/docs", "version": "0.0.0", - "private": true + "private": true, + "devDependencies": { + "@rallly/tsconfig": "*" + } } diff --git a/apps/docs/tsconfig.json b/apps/docs/tsconfig.json new file mode 100644 index 000000000..4ad2dd442 --- /dev/null +++ b/apps/docs/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "@rallly/tsconfig/next.json", + "include": ["**/*.ts", "**/*.tsx", "**/*.js"], + "exclude": ["node_modules"] +} diff --git a/apps/landing/.eslintrc.js b/apps/landing/.eslintrc.js new file mode 100644 index 000000000..3d9be6e61 --- /dev/null +++ b/apps/landing/.eslintrc.js @@ -0,0 +1,4 @@ +/** @type {import("eslint").Linter.Config} */ +module.exports = { + ...require("@rallly/eslint-config")(__dirname), +}; diff --git a/apps/landing/package.json b/apps/landing/package.json index 4d64deceb..ba031e129 100644 --- a/apps/landing/package.json +++ b/apps/landing/package.json @@ -20,7 +20,6 @@ "@svgr/webpack": "^6.5.1", "@tailwindcss/typography": "^0.5.9", "@vercel/analytics": "^0.1.8", - "@vercel/og": "^0.5.11", "autoprefixer": "^10.4.13", "class-variance-authority": "^0.6.0", "dayjs": "^1.11.7", @@ -50,15 +49,8 @@ "@types/smoothscroll-polyfill": "^0.3.1", "cheerio": "^1.0.0-rc.12", "cross-env": "^7.0.3", - "eslint-config-turbo": "^0.0.9", - "eslint-import-resolver-typescript": "^2.7.0", - "eslint-plugin-import": "^2.22.1", - "eslint-plugin-react": "^7.23.2", - "eslint-plugin-react-hooks": "^4.2.0", - "eslint-plugin-simple-import-sort": "^7.0.0", "i18next-scanner": "^4.2.0", "i18next-scanner-typescript": "^1.1.1", - "prettier-plugin-tailwindcss": "^0.1.8", "smtp-tester": "^2.0.1", "wait-on": "^6.0.1" } diff --git a/apps/landing/src/components/error-page.tsx b/apps/landing/src/components/error-page.tsx index 12621b667..9259230e8 100644 --- a/apps/landing/src/components/error-page.tsx +++ b/apps/landing/src/components/error-page.tsx @@ -1,4 +1,4 @@ -import { FrownIcon } from "@rallly/icons"; +import { FrownIcon } from "lucide-react"; import Head from "next/head"; import Link from "next/link"; import { useTranslation } from "next-i18next"; diff --git a/apps/landing/src/components/home/bonus.tsx b/apps/landing/src/components/home/bonus.tsx index 6a4fc1e76..fa98a7cf2 100644 --- a/apps/landing/src/components/home/bonus.tsx +++ b/apps/landing/src/components/home/bonus.tsx @@ -1,11 +1,11 @@ +import { cn } from "@rallly/ui"; +import { m } from "framer-motion"; import { CalendarCheck2Icon, LanguagesIcon, Users2Icon, ZapIcon, -} from "@rallly/icons"; -import { cn } from "@rallly/ui"; -import { m } from "framer-motion"; +} from "lucide-react"; import { Trans } from "@/components/trans"; import { IconComponent } from "@/types"; diff --git a/apps/landing/src/components/home/color-hash.ts b/apps/landing/src/components/home/color-hash.ts index 9e03aaedd..93721495b 100644 --- a/apps/landing/src/components/home/color-hash.ts +++ b/apps/landing/src/components/home/color-hash.ts @@ -40,7 +40,7 @@ function isBright(color: RGBColor): boolean { export const getRandomAvatarColor = (str: string) => { const strSum = str.split("").reduce((acc, val) => acc + val.charCodeAt(0), 0); const randomIndex = strSum % avatarBackgroundColors.length; - const color = avatarBackgroundColors[randomIndex]; + const color = avatarBackgroundColors[randomIndex] as RGBColor; const [r, g, b] = color; return { color: `rgb(${r}, ${g}, ${b})`, requiresDarkText: isBright(color) }; }; diff --git a/apps/landing/src/components/home/hero.tsx b/apps/landing/src/components/home/hero.tsx index 9668bf887..cd5fa3e56 100644 --- a/apps/landing/src/components/home/hero.tsx +++ b/apps/landing/src/components/home/hero.tsx @@ -1,8 +1,8 @@ -import { ChevronRightIcon } from "@rallly/icons"; import { Badge } from "@rallly/ui/badge"; import { Button } from "@rallly/ui/button"; import { preventWidows } from "@rallly/utils"; import { m } from "framer-motion"; +import { ChevronRightIcon } from "lucide-react"; import Image from "next/image"; import Link from "next/link"; import * as React from "react"; diff --git a/apps/landing/src/components/layouts/blog-layout.tsx b/apps/landing/src/components/layouts/blog-layout.tsx index 969d6ed5f..06194eb06 100644 --- a/apps/landing/src/components/layouts/blog-layout.tsx +++ b/apps/landing/src/components/layouts/blog-layout.tsx @@ -1,4 +1,4 @@ -import { NewspaperIcon } from "@rallly/icons"; +import { NewspaperIcon } from "lucide-react"; import Script from "next/script"; import PageLayout from "@/components/layouts/page-layout"; diff --git a/apps/landing/src/components/layouts/page-layout.tsx b/apps/landing/src/components/layouts/page-layout.tsx index d73055342..d4a1fa3b6 100644 --- a/apps/landing/src/components/layouts/page-layout.tsx +++ b/apps/landing/src/components/layouts/page-layout.tsx @@ -1,4 +1,3 @@ -import { ChevronRightIcon, MenuIcon } from "@rallly/icons"; import { cn } from "@rallly/ui"; import { DropdownMenu, @@ -7,6 +6,7 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from "@rallly/ui/dropdown-menu"; +import { ChevronRightIcon, MenuIcon } from "lucide-react"; import Image from "next/image"; import Link from "next/link"; import { useRouter } from "next/router"; diff --git a/apps/landing/src/components/layouts/page-layout/footer.tsx b/apps/landing/src/components/layouts/page-layout/footer.tsx index c70de6683..485acd739 100644 --- a/apps/landing/src/components/layouts/page-layout/footer.tsx +++ b/apps/landing/src/components/layouts/page-layout/footer.tsx @@ -1,10 +1,4 @@ -import { - DiscordIcon, - GithubIcon, - LanguagesIcon, - LinkedinIcon, - TwitterIcon, -} from "@rallly/icons"; +import { DiscordIcon } from "@rallly/icons"; import languages from "@rallly/languages"; import { Select, @@ -13,6 +7,12 @@ import { SelectTrigger, SelectValue, } from "@rallly/ui/select"; +import { + GithubIcon, + LanguagesIcon, + LinkedinIcon, + TwitterIcon, +} from "lucide-react"; import Image from "next/image"; import Link from "next/link"; import { useRouter } from "next/router"; diff --git a/apps/landing/src/components/marketing.tsx b/apps/landing/src/components/marketing.tsx index 893eba245..d42e92f44 100644 --- a/apps/landing/src/components/marketing.tsx +++ b/apps/landing/src/components/marketing.tsx @@ -1,5 +1,5 @@ -import { ArrowUpRight } from "@rallly/icons"; import { m } from "framer-motion"; +import { ArrowUpRight } from "lucide-react"; import Image from "next/image"; import Link from "next/link"; import { NextSeo } from "next-seo"; diff --git a/apps/landing/src/pages/404.tsx b/apps/landing/src/pages/404.tsx index 6a0cdc20c..e1a076c16 100644 --- a/apps/landing/src/pages/404.tsx +++ b/apps/landing/src/pages/404.tsx @@ -1,4 +1,4 @@ -import { FileSearchIcon } from "@rallly/icons"; +import { FileSearchIcon } from "lucide-react"; import { GetStaticProps } from "next"; import { useTranslation } from "next-i18next"; import { serverSideTranslations } from "next-i18next/serverSideTranslations"; diff --git a/apps/landing/src/pages/api/og-image.tsx b/apps/landing/src/pages/api/og-image.tsx index 2cbe6d767..16d7235af 100644 --- a/apps/landing/src/pages/api/og-image.tsx +++ b/apps/landing/src/pages/api/og-image.tsx @@ -1,5 +1,5 @@ /* eslint-disable @next/next/no-img-element */ -import { ImageResponse } from "@vercel/og"; +import { ImageResponse } from "next/og"; import { NextRequest } from "next/server"; export const config = { diff --git a/apps/landing/src/pages/blog/[slug].tsx b/apps/landing/src/pages/blog/[slug].tsx index fc6db6656..ab817380b 100644 --- a/apps/landing/src/pages/blog/[slug].tsx +++ b/apps/landing/src/pages/blog/[slug].tsx @@ -1,4 +1,4 @@ -import { ArrowLeftIcon } from "@rallly/icons"; +import { ArrowLeftIcon } from "lucide-react"; import { GetStaticPropsContext } from "next"; import ErrorPage from "next/error"; import Head from "next/head"; @@ -117,6 +117,8 @@ export async function getStaticProps(ctx: GetStaticPropsContext) { }, }; } + + return res; } export async function getStaticPaths() { diff --git a/apps/landing/src/pages/pricing.tsx b/apps/landing/src/pages/pricing.tsx index a7474a6d8..d833277ad 100644 --- a/apps/landing/src/pages/pricing.tsx +++ b/apps/landing/src/pages/pricing.tsx @@ -1,4 +1,3 @@ -import { TrendingUpIcon } from "@rallly/icons"; import { BillingPlan, BillingPlanDescription, @@ -11,6 +10,7 @@ import { } from "@rallly/ui/billing-plan"; import { Button } from "@rallly/ui/button"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@rallly/ui/tabs"; +import { TrendingUpIcon } from "lucide-react"; import Link from "next/link"; import { useTranslation } from "next-i18next"; import { NextSeo } from "next-seo"; diff --git a/apps/landing/tsconfig.json b/apps/landing/tsconfig.json index bfe5fb18a..e259cb9d5 100644 --- a/apps/landing/tsconfig.json +++ b/apps/landing/tsconfig.json @@ -1,24 +1,13 @@ { + "extends": "@rallly/tsconfig/next.json", "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["src/*"], "~/*": ["public/*"] }, - "lib": ["dom", "dom.iterable", "esnext"], - "allowJs": true, - "skipLibCheck": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "noEmit": true, - "incremental": true, - "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "preserve" + "checkJs": false }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "next-i18next.config.js"], - "exclude": ["node_modules", "**/*.js"] + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] } diff --git a/.env.test b/apps/web/.env.test similarity index 59% rename from .env.test rename to apps/web/.env.test index 294497791..bfd50acbf 100644 --- a/.env.test +++ b/apps/web/.env.test @@ -2,5 +2,5 @@ PORT=3002 NEXT_PUBLIC_BASE_URL=http://localhost:3002 NEXTAUTH_URL=http://localhost:3002 SECRET_PASSWORD=abcdefghijklmnopqrstuvwxyz1234567890 -DATABASE_URL=postgres://postgres:postgres@localhost:5432/rallly -SUPPORT_EMAIL=support@rallly.co \ No newline at end of file +DATABASE_URL=postgres://postgres:postgres@localhost:5450/db +SUPPORT_EMAIL=support@rallly.co diff --git a/apps/web/.eslintrc.js b/apps/web/.eslintrc.js new file mode 100644 index 000000000..3d9be6e61 --- /dev/null +++ b/apps/web/.eslintrc.js @@ -0,0 +1,4 @@ +/** @type {import("eslint").Linter.Config} */ +module.exports = { + ...require("@rallly/eslint-config")(__dirname), +}; diff --git a/apps/web/declarations/i18next.d.ts b/apps/web/declarations/i18next.d.ts index 25e3fcb59..9ded39e18 100644 --- a/apps/web/declarations/i18next.d.ts +++ b/apps/web/declarations/i18next.d.ts @@ -1,4 +1,4 @@ -import "react-i18next"; +import "i18next"; import app from "../public/locales/en/app.json"; diff --git a/apps/web/next-env.d.ts b/apps/web/next-env.d.ts index 4f11a03dc..fd36f9494 100644 --- a/apps/web/next-env.d.ts +++ b/apps/web/next-env.d.ts @@ -1,5 +1,6 @@ /// /// +/// // NOTE: This file should not be edited // see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/apps/web/next.config.js b/apps/web/next.config.js index ed2cad4dc..02cedd428 100644 --- a/apps/web/next.config.js +++ b/apps/web/next.config.js @@ -4,17 +4,16 @@ // https://docs.sentry.io/platforms/javascript/guides/nextjs/ const { withSentryConfig } = require("@sentry/nextjs"); -const i18n = require("./i18n.config.js"); const withBundleAnalyzer = require("@next/bundle-analyzer")({ enabled: process.env.ANALYZE === "true", }); +/** @type {import('next').NextConfig} */ const nextConfig = { - i18n: { ...i18n, localeDetection: false }, productionBrowserSourceMaps: true, - output: "standalone", transpilePackages: [ "@rallly/backend", + "@rallly/database", "@rallly/icons", "@rallly/ui", "@rallly/tailwind-config", @@ -22,12 +21,14 @@ const nextConfig = { webpack(config) { config.module.rules.push({ test: /\.svg$/, - issuer: /\.[jt]sx?$/, use: ["@svgr/webpack"], }); return config; }, + eslint: { + ignoreDuringBuilds: true, + }, typescript: { ignoreBuildErrors: true, }, @@ -61,6 +62,7 @@ const sentryWebpackPluginOptions = { // recommended: // release, url, org, project, authToken, configFile, stripPrefix, // urlPrefix, include, ignore + authToken: process.env.SENTRY_AUTH_TOKEN, dryRun: !process.env.SENTRY_AUTH_TOKEN, silent: true, // Suppresses all logs // For all available options, see: diff --git a/apps/web/package.json b/apps/web/package.json index b7a75243a..a7d8711ee 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -3,8 +3,9 @@ "version": "0.0.0", "private": true, "scripts": { - "dev": "cross-env TAILWIND_MODE=watch next dev", + "dev": "next dev", "build": "next build", + "build:test": "dotenv -e .env.test -- next build", "analyze": "cross-env ANALYZE=true next build", "start": "next start", "lint": "eslint .", @@ -29,7 +30,6 @@ "@rallly/languages": "*", "@rallly/tailwind-config": "*", "@rallly/ui": "*", - "@sentry/nextjs": "^7.74.1", "@svgr/webpack": "^6.5.1", "@tailwindcss/typography": "^0.5.9", "@tanstack/react-query": "^4.0.0", @@ -37,7 +37,6 @@ "@trpc/client": "^10.13.0", "@trpc/next": "^10.13.0", "@trpc/react-query": "^10.13.0", - "@vercel/og": "^0.5.13", "accept-language-parser": "^1.5.0", "autoprefixer": "^10.4.13", "class-variance-authority": "^0.6.0", @@ -48,6 +47,7 @@ "dayjs": "^1.11.10", "i18next": "^22.4.9", "i18next-icu": "^2.3.0", + "i18next-resources-to-backend": "^1.1.4", "ics": "^3.1.0", "intl-messageformat": "^10.3.4", "iron-session": "^6.3.1", @@ -72,11 +72,12 @@ "smoothscroll-polyfill": "^0.4.4", "spacetime": "^7.4.7", "superjson": "^2.0.0", - "timezone-soft": "^1.4.1" + "timezone-soft": "^1.5.1" }, "devDependencies": { - "@playwright/test": "^1.35.1", + "@playwright/test": "^1.39.0", "@rallly/tsconfig": "*", + "@rallly/eslint-config": "*", "@types/accept-language-parser": "^1.5.3", "@types/color-hash": "^1.0.2", "@types/lodash": "^4.14.178", @@ -87,15 +88,8 @@ "@types/smoothscroll-polyfill": "^0.3.1", "cheerio": "^1.0.0-rc.12", "cross-env": "^7.0.3", - "eslint-config-turbo": "^0.0.9", - "eslint-import-resolver-typescript": "^2.7.0", - "eslint-plugin-import": "^2.22.1", - "eslint-plugin-react": "^7.23.2", - "eslint-plugin-react-hooks": "^4.2.0", - "eslint-plugin-simple-import-sort": "^7.0.0", "i18next-scanner": "^4.2.0", "i18next-scanner-typescript": "^1.1.1", - "prettier-plugin-tailwindcss": "^0.1.8", "smtp-tester": "^2.0.1", "wait-on": "^6.0.1" } diff --git a/apps/web/playwright.config.ts b/apps/web/playwright.config.ts index f480b3281..2389bbaa3 100644 --- a/apps/web/playwright.config.ts +++ b/apps/web/playwright.config.ts @@ -4,7 +4,7 @@ import path from "path"; const ci = process.env.CI === "true"; -dotenv.config({ path: path.resolve(__dirname, "../../", ".env.test") }); +dotenv.config({ path: path.resolve(__dirname, ".env.test") }); // Use process.env.PORT by default and fallback to port 3000 const PORT = process.env.PORT || 3000; @@ -24,13 +24,9 @@ const config: PlaywrightTestConfig = { trace: "retain-on-failure", }, webServer: { - command: `NODE_ENV=test yarn dev --port ${PORT}`, + command: `NODE_ENV=test yarn start --port ${PORT}`, url: baseURL, - timeout: 120 * 1000, - reuseExistingServer: !ci, - }, - expect: { - timeout: 10000, // 10 seconds + reuseExistingServer: !process.env.CI, }, reporter: [ [ci ? "github" : "list"], diff --git a/apps/web/postcss.config.js b/apps/web/postcss.config.js index f46b31c99..12a703d90 100644 --- a/apps/web/postcss.config.js +++ b/apps/web/postcss.config.js @@ -1,3 +1,6 @@ module.exports = { - plugins: ["tailwindcss", "autoprefixer"], + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, }; diff --git a/apps/web/public/locales/en/app.json b/apps/web/public/locales/en/app.json index d96ea55ba..f9153ac6f 100644 --- a/apps/web/public/locales/en/app.json +++ b/apps/web/public/locales/en/app.json @@ -225,5 +225,6 @@ "authErrorCta": "Go to login page", "continueAs": "Continue as", "finalizeFeature": "Finalize", - "duplicateFeature": "Duplicate" + "duplicateFeature": "Duplicate", + "pageMovedDescription": "Redirecting to {newUrl}" } diff --git a/apps/web/src/app/[locale]/(admin)/layout.tsx b/apps/web/src/app/[locale]/(admin)/layout.tsx new file mode 100644 index 000000000..dbe60c4ce --- /dev/null +++ b/apps/web/src/app/[locale]/(admin)/layout.tsx @@ -0,0 +1,6 @@ +"use client"; +import { StandardLayout } from "@/components/layouts/standard-layout"; + +export default function Layout({ children }: { children: React.ReactNode }) { + return {children}; +} diff --git a/apps/web/src/app/[locale]/(admin)/new/page.tsx b/apps/web/src/app/[locale]/(admin)/new/page.tsx new file mode 100644 index 000000000..9d80dd373 --- /dev/null +++ b/apps/web/src/app/[locale]/(admin)/new/page.tsx @@ -0,0 +1,17 @@ +import { getTranslation } from "@/app/i18n"; +import { CreatePoll } from "@/components/create-poll"; + +export default function Page() { + return ; +} + +export async function generateMetadata({ + params, +}: { + params: { locale: string }; +}) { + const { t } = await getTranslation(params.locale); + return { + title: t("newPoll"), + }; +} diff --git a/apps/web/src/pages/poll/[urlId]/duplicate.tsx b/apps/web/src/app/[locale]/(admin)/poll/[urlId]/duplicate/page.tsx similarity index 89% rename from apps/web/src/pages/poll/[urlId]/duplicate.tsx rename to apps/web/src/app/[locale]/(admin)/poll/[urlId]/duplicate/page.tsx index fa6c7cde8..97f05078e 100644 --- a/apps/web/src/pages/poll/[urlId]/duplicate.tsx +++ b/apps/web/src/app/[locale]/(admin)/poll/[urlId]/duplicate/page.tsx @@ -1,3 +1,4 @@ +"use client"; import { zodResolver } from "@hookform/resolvers/zod"; import { Button } from "@rallly/ui/button"; import { @@ -17,18 +18,16 @@ import { } from "@rallly/ui/form"; import { Input } from "@rallly/ui/input"; import Link from "next/link"; -import { useRouter } from "next/router"; +import { useRouter } from "next/navigation"; import { useForm } from "react-hook-form"; import { z } from "zod"; -import { getPollLayout } from "@/components/layouts/poll-layout"; import { PayWall } from "@/components/pay-wall"; import { usePoll } from "@/components/poll-context"; import { Trans } from "@/components/trans"; import { NextPageWithLayout } from "@/types"; import { usePostHog } from "@/utils/posthog"; import { trpc } from "@/utils/trpc/client"; -import { getStaticTranslations } from "@/utils/with-page-translations"; const formSchema = z.object({ title: z.string().trim().min(1), @@ -63,7 +62,7 @@ const Page: NextPageWithLayout = () => { pollId: poll.id, newPollId: res.id, }); - await router.push(`/poll/${res.id}`); + router.push(`/poll/${res.id}`); }, }, ); @@ -124,15 +123,4 @@ const Page: NextPageWithLayout = () => { ); }; -Page.getLayout = getPollLayout; - -export const getStaticPaths = async () => { - return { - paths: [], - fallback: "blocking", - }; -}; - -export const getStaticProps = getStaticTranslations; - export default Page; diff --git a/apps/web/src/pages/poll/[urlId]/edit-details.tsx b/apps/web/src/app/[locale]/(admin)/poll/[urlId]/edit-details/page.tsx similarity index 86% rename from apps/web/src/pages/poll/[urlId]/edit-details.tsx rename to apps/web/src/app/[locale]/(admin)/poll/[urlId]/edit-details/page.tsx index cb117ec77..7e9efbfcc 100644 --- a/apps/web/src/pages/poll/[urlId]/edit-details.tsx +++ b/apps/web/src/app/[locale]/(admin)/poll/[urlId]/edit-details/page.tsx @@ -1,3 +1,4 @@ +"use client"; import { Button } from "@rallly/ui/button"; import { Card, @@ -9,19 +10,17 @@ import { } from "@rallly/ui/card"; import { Form } from "@rallly/ui/form"; import Link from "next/link"; -import { useRouter } from "next/router"; +import { useRouter } from "next/navigation"; import { useForm } from "react-hook-form"; import { PollDetailsData, PollDetailsForm, } from "@/components/forms/poll-details-form"; -import { getPollLayout } from "@/components/layouts/poll-layout"; import { useUpdatePollMutation } from "@/components/poll/mutations"; import { usePoll } from "@/components/poll-context"; import { Trans } from "@/components/trans"; import { NextPageWithLayout } from "@/types"; -import { getStaticTranslations } from "@/utils/with-page-translations"; const Page: NextPageWithLayout = () => { const { poll } = usePoll(); @@ -87,15 +86,4 @@ const Page: NextPageWithLayout = () => { ); }; -Page.getLayout = getPollLayout; - -export const getStaticPaths = async () => { - return { - paths: [], - fallback: "blocking", - }; -}; - -export const getStaticProps = getStaticTranslations; - export default Page; diff --git a/apps/web/src/pages/poll/[urlId]/edit-options.tsx b/apps/web/src/app/[locale]/(admin)/poll/[urlId]/edit-options/page.tsx similarity index 88% rename from apps/web/src/pages/poll/[urlId]/edit-options.tsx rename to apps/web/src/app/[locale]/(admin)/poll/[urlId]/edit-options/page.tsx index 6015e422b..fdde82681 100644 --- a/apps/web/src/pages/poll/[urlId]/edit-options.tsx +++ b/apps/web/src/app/[locale]/(admin)/poll/[urlId]/edit-options/page.tsx @@ -1,22 +1,20 @@ +"use client"; import { Button } from "@rallly/ui/button"; import { CardFooter } from "@rallly/ui/card"; import { Form } from "@rallly/ui/form"; import dayjs from "dayjs"; import Link from "next/link"; -import { useRouter } from "next/router"; +import { useRouter } from "next/navigation"; import { useTranslation } from "next-i18next"; import { useForm } from "react-hook-form"; import { PollOptionsData } from "@/components/forms"; import PollOptionsForm from "@/components/forms/poll-options-form"; -import { getPollLayout } from "@/components/layouts/poll-layout"; import { useModalContext } from "@/components/modal/modal-provider"; import { useUpdatePollMutation } from "@/components/poll/mutations"; import { usePoll } from "@/components/poll-context"; import { Trans } from "@/components/trans"; -import { NextPageWithLayout } from "@/types"; import { encodeDateOption } from "@/utils/date-time-utils"; -import { getStaticTranslations } from "@/utils/with-page-translations"; const convertOptionToString = (option: { start: Date; duration: number }) => { const start = dayjs(option.start).utc(); @@ -27,7 +25,7 @@ const convertOptionToString = (option: { start: Date; duration: number }) => { .format("YYYY-MM-DDTHH:mm:ss")}`; }; -const Page: NextPageWithLayout = () => { +const Page = () => { const { poll, getParticipantsWhoVotedForOption } = usePoll(); const { mutate: updatePollMutation, isLoading: isUpdating } = useUpdatePollMutation(); @@ -136,15 +134,4 @@ const Page: NextPageWithLayout = () => { ); }; -Page.getLayout = getPollLayout; - -export const getStaticPaths = async () => { - return { - paths: [], //indicates that no page needs be created at build time - fallback: "blocking", //indicates the type of fallback - }; -}; - -export const getStaticProps = getStaticTranslations; - export default Page; diff --git a/apps/web/src/pages/poll/[urlId]/edit-settings.tsx b/apps/web/src/app/[locale]/(admin)/poll/[urlId]/edit-settings/page.tsx similarity index 79% rename from apps/web/src/pages/poll/[urlId]/edit-settings.tsx rename to apps/web/src/app/[locale]/(admin)/poll/[urlId]/edit-settings/page.tsx index a56388169..b6ef51852 100644 --- a/apps/web/src/pages/poll/[urlId]/edit-settings.tsx +++ b/apps/web/src/app/[locale]/(admin)/poll/[urlId]/edit-settings/page.tsx @@ -1,22 +1,20 @@ +"use client"; import { Button } from "@rallly/ui/button"; import { CardFooter } from "@rallly/ui/card"; import { Form } from "@rallly/ui/form"; import Link from "next/link"; -import { useRouter } from "next/router"; +import { useRouter } from "next/navigation"; import { useForm } from "react-hook-form"; import { PollSettingsForm, PollSettingsFormData, } from "@/components/forms/poll-settings"; -import { getPollLayout } from "@/components/layouts/poll-layout"; import { useUpdatePollMutation } from "@/components/poll/mutations"; import { Trans } from "@/components/trans"; import { usePoll } from "@/contexts/poll"; -import { NextPageWithLayout } from "@/types"; -import { getStaticTranslations } from "@/utils/with-page-translations"; -const Page: NextPageWithLayout = () => { +const Page = () => { const poll = usePoll(); const router = useRouter(); @@ -69,15 +67,4 @@ const Page: NextPageWithLayout = () => { ); }; -Page.getLayout = getPollLayout; - -export const getStaticPaths = async () => { - return { - paths: [], - fallback: "blocking", - }; -}; - -export const getStaticProps = getStaticTranslations; - export default Page; diff --git a/apps/web/src/pages/poll/[urlId]/finalize.tsx b/apps/web/src/app/[locale]/(admin)/poll/[urlId]/finalize/page.tsx similarity index 86% rename from apps/web/src/pages/poll/[urlId]/finalize.tsx rename to apps/web/src/app/[locale]/(admin)/poll/[urlId]/finalize/page.tsx index 949d29631..3ffecaf78 100644 --- a/apps/web/src/pages/poll/[urlId]/finalize.tsx +++ b/apps/web/src/app/[locale]/(admin)/poll/[urlId]/finalize/page.tsx @@ -1,3 +1,4 @@ +"use client"; import { Button } from "@rallly/ui/button"; import { CardContent, @@ -6,10 +7,9 @@ import { CardHeader, CardTitle, } from "@rallly/ui/card"; -import { useRouter } from "next/router"; +import { useRouter } from "next/navigation"; import { Card } from "@/components/card"; -import { getPollLayout } from "@/components/layouts/poll-layout"; import { PayWall } from "@/components/pay-wall"; import { FinalizePollForm } from "@/components/poll/manage-poll/finalize-poll-dialog"; import { Trans } from "@/components/trans"; @@ -18,7 +18,6 @@ import { usePoll } from "@/contexts/poll"; import { NextPageWithLayout } from "@/types"; import { usePostHog } from "@/utils/posthog"; import { trpc } from "@/utils/trpc/client"; -import { getStaticTranslations } from "@/utils/with-page-translations"; const FinalizationForm = () => { const plan = usePlan(); @@ -94,15 +93,4 @@ const Page: NextPageWithLayout = () => { ); }; -Page.getLayout = getPollLayout; - -export const getStaticPaths = async () => { - return { - paths: [], - fallback: "blocking", - }; -}; - -export const getStaticProps = getStaticTranslations; - export default Page; diff --git a/apps/web/src/app/[locale]/(admin)/poll/[urlId]/layout.tsx b/apps/web/src/app/[locale]/(admin)/poll/[urlId]/layout.tsx new file mode 100644 index 000000000..91a446536 --- /dev/null +++ b/apps/web/src/app/[locale]/(admin)/poll/[urlId]/layout.tsx @@ -0,0 +1,31 @@ +import { prisma } from "@rallly/database"; +import { notFound } from "next/navigation"; + +import { PollLayout } from "@/components/layouts/poll-layout"; + +export default async function Layout({ + children, + params, +}: React.PropsWithChildren<{ params: { urlId: string } }>) { + const poll = await prisma.poll.findUnique({ where: { id: params.urlId } }); + if (!poll) { + notFound(); + } + + return {children}; +} + +export async function generateMetadata({ + params, +}: { + params: { locale: string; urlId: string }; +}) { + const poll = await prisma.poll.findUnique({ where: { id: params.urlId } }); + + if (!poll) { + return notFound(); + } + return { + title: poll.title, + }; +} diff --git a/apps/web/src/pages/poll/[urlId].tsx b/apps/web/src/app/[locale]/(admin)/poll/[urlId]/page.tsx similarity index 72% rename from apps/web/src/pages/poll/[urlId].tsx rename to apps/web/src/app/[locale]/(admin)/poll/[urlId]/page.tsx index 313f9d8b2..3159f05fa 100644 --- a/apps/web/src/pages/poll/[urlId].tsx +++ b/apps/web/src/app/[locale]/(admin)/poll/[urlId]/page.tsx @@ -1,17 +1,14 @@ -import { InfoIcon } from "@rallly/icons"; +"use client"; import { cn } from "@rallly/ui"; import { Alert, AlertDescription, AlertTitle } from "@rallly/ui/alert"; +import { InfoIcon } from "lucide-react"; import { Trans } from "next-i18next"; -import { getPollLayout } from "@/components/layouts/poll-layout"; import { LoginLink } from "@/components/login-link"; import { Poll } from "@/components/poll"; import { RegisterLink } from "@/components/register-link"; import { useUser } from "@/components/user-provider"; import { usePoll } from "@/contexts/poll"; -import { NextPageWithLayout } from "@/types"; -import { isSelfHosted } from "@/utils/constants"; -import { getStaticTranslations } from "@/utils/with-page-translations"; const GuestPollAlert = () => { const poll = usePoll(); @@ -49,25 +46,11 @@ const GuestPollAlert = () => { ); }; -const Page: NextPageWithLayout = () => { +export default function Page() { return (
); -}; - -Page.getLayout = getPollLayout; -Page.isAuthRequired = isSelfHosted; - -export const getStaticPaths = async () => { - return { - paths: [], - fallback: "blocking", - }; -}; - -export const getStaticProps = getStaticTranslations; - -export default Page; +} diff --git a/apps/web/src/app/[locale]/(admin)/polls/page.tsx b/apps/web/src/app/[locale]/(admin)/polls/page.tsx new file mode 100644 index 000000000..d6257a7fd --- /dev/null +++ b/apps/web/src/app/[locale]/(admin)/polls/page.tsx @@ -0,0 +1,18 @@ +import { getTranslation } from "@/app/i18n"; + +import { PollsPage } from "./polls-page"; + +export default function Page() { + return ; +} + +export async function generateMetadata({ + params, +}: { + params: { locale: string }; +}) { + const { t } = await getTranslation(params.locale); + return { + title: t("polls"), + }; +} diff --git a/apps/web/src/pages/polls.tsx b/apps/web/src/app/[locale]/(admin)/polls/polls-page.tsx similarity index 91% rename from apps/web/src/pages/polls.tsx rename to apps/web/src/app/[locale]/(admin)/polls/polls-page.tsx index da92b3611..8e5d2a2b2 100644 --- a/apps/web/src/pages/polls.tsx +++ b/apps/web/src/app/[locale]/(admin)/polls/polls-page.tsx @@ -1,19 +1,17 @@ +"use client"; +import { Button } from "@rallly/ui/button"; +import dayjs from "dayjs"; import { InboxIcon, PauseCircleIcon, PlusIcon, RadioIcon, VoteIcon, -} from "@rallly/icons"; -import { Button } from "@rallly/ui/button"; -import dayjs from "dayjs"; -import Head from "next/head"; +} from "lucide-react"; import Link from "next/link"; -import { useTranslation } from "next-i18next"; import { Container } from "@/components/container"; import { DateIcon } from "@/components/date-icon"; -import { getStandardLayout } from "@/components/layouts/standard-layout"; import { TopBar, TopBarTitle, @@ -22,11 +20,8 @@ import { ParticipantAvatarBar } from "@/components/participant-avatar-bar"; import { PollStatusBadge } from "@/components/poll-status"; import { Skeleton } from "@/components/skeleton"; import { Trans } from "@/components/trans"; -import { NextPageWithLayout } from "@/types"; -import { isSelfHosted } from "@/utils/constants"; import { useDayjs } from "@/utils/dayjs"; import { trpc } from "@/utils/trpc/client"; -import { getStaticTranslations } from "@/utils/with-page-translations"; const EmptyState = () => { return ( @@ -57,16 +52,12 @@ const EmptyState = () => { ); }; -const Page: NextPageWithLayout = () => { +export function PollsPage() { const { data } = trpc.polls.list.useQuery(); - const { t } = useTranslation(); const { adjustTimeZone } = useDayjs(); return (
- - {t("polls")} - } icon={VoteIcon} />
@@ -185,11 +176,4 @@ const Page: NextPageWithLayout = () => {
); -}; - -Page.getLayout = getStandardLayout; -Page.isAuthRequired = isSelfHosted; - -export default Page; - -export const getStaticProps = getStaticTranslations; +} diff --git a/apps/web/src/pages/settings/billing.tsx b/apps/web/src/app/[locale]/(admin)/settings/billing/billing-page.tsx similarity index 69% rename from apps/web/src/pages/settings/billing.tsx rename to apps/web/src/app/[locale]/(admin)/settings/billing/billing-page.tsx index 36095037f..1a89a24cc 100644 --- a/apps/web/src/pages/settings/billing.tsx +++ b/apps/web/src/app/[locale]/(admin)/settings/billing/billing-page.tsx @@ -1,16 +1,15 @@ -import { ArrowUpRight, CreditCardIcon, SendIcon } from "@rallly/icons"; +"use client"; import { Button } from "@rallly/ui/button"; import { Card } from "@rallly/ui/card"; import { Label } from "@rallly/ui/label"; import dayjs from "dayjs"; -import { GetStaticProps } from "next"; +import { ArrowUpRight, CreditCardIcon, SendIcon } from "lucide-react"; import Head from "next/head"; import Link from "next/link"; import Script from "next/script"; import { useTranslation } from "next-i18next"; import { BillingPlans } from "@/components/billing/billing-plans"; -import { getProfileLayout } from "@/components/layouts/profile-layout"; import { Settings, SettingsContent, @@ -19,12 +18,8 @@ import { } from "@/components/settings/settings"; import { Trans } from "@/components/trans"; import { useSubscription } from "@/contexts/plan"; -import { isSelfHosted } from "@/utils/constants"; import { trpc } from "@/utils/trpc/client"; -import { NextPageWithLayout } from "../../types"; -import { getStaticTranslations } from "../../utils/with-page-translations"; - declare global { interface Window { // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -61,11 +56,7 @@ const BillingPortal = () => { ); }; -export const proPlanIdMonthly = process.env - .NEXT_PUBLIC_PRO_PLAN_ID_MONTHLY as string; - -export const proPlanIdYearly = process.env - .NEXT_PUBLIC_PRO_PLAN_ID_YEARLY as string; +const proPlanIdMonthly = process.env.NEXT_PUBLIC_PRO_PLAN_ID_MONTHLY as string; const SubscriptionStatus = () => { const data = useSubscription(); @@ -106,7 +97,7 @@ const LegacyBilling = () => { } return ( - + <> {process.env.NEXT_PUBLIC_PADDLE_VENDOR_ID ? (