mirror of
https://github.com/lukevella/rallly.git
synced 2025-04-28 09:46:39 +02:00
♻️ Replace yarn with pnpm (#1693)
This commit is contained in:
parent
c8e78841f1
commit
765a97f3c6
59 changed files with 17816 additions and 16954 deletions
|
@ -11,3 +11,11 @@ docker-compose.yml
|
|||
/docs
|
||||
README.md
|
||||
node_modules
|
||||
|
||||
# Build outputs
|
||||
apps/*/.next
|
||||
apps/*/dist
|
||||
packages/*/dist
|
||||
|
||||
# Turbo prune output
|
||||
out/
|
||||
|
|
8
.github/actions/pnpm-install/action.yml
vendored
Normal file
8
.github/actions/pnpm-install/action.yml
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
name: "Pnpm Install"
|
||||
description: "Runs pnpm install with --frozen-lockfile"
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Run pnpm install
|
||||
run: pnpm install --frozen-lockfile
|
||||
shell: bash
|
5
.github/actions/setup-node/action.yml
vendored
5
.github/actions/setup-node/action.yml
vendored
|
@ -8,10 +8,13 @@ inputs:
|
|||
cache:
|
||||
description: "Package manager for caching"
|
||||
required: false
|
||||
default: "yarn"
|
||||
default: "pnpm"
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
|
|
8
.github/actions/yarn-install/action.yml
vendored
8
.github/actions/yarn-install/action.yml
vendored
|
@ -1,8 +0,0 @@
|
|||
name: "Yarn Install"
|
||||
description: "Runs yarn install with --frozen-lockfile"
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Run yarn install
|
||||
run: yarn install --frozen-lockfile
|
||||
shell: bash
|
32
.github/workflows/ci.yml
vendored
32
.github/workflows/ci.yml
vendored
|
@ -18,10 +18,13 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/setup-node
|
||||
- uses: ./.github/actions/yarn-install
|
||||
- uses: ./.github/actions/pnpm-install
|
||||
|
||||
- name: Generate Prisma Client
|
||||
run: pnpm db:generate
|
||||
|
||||
- name: Check types
|
||||
run: yarn type-check
|
||||
run: pnpm type-check
|
||||
|
||||
sherif:
|
||||
name: Sherif
|
||||
|
@ -31,7 +34,7 @@ jobs:
|
|||
- uses: ./.github/actions/setup-node
|
||||
|
||||
- name: Run sherif
|
||||
run: npx sherif@latest
|
||||
run: pnpm dlx sherif@latest
|
||||
|
||||
linting:
|
||||
name: Linting
|
||||
|
@ -39,10 +42,10 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/setup-node
|
||||
- uses: ./.github/actions/yarn-install
|
||||
- uses: ./.github/actions/pnpm-install
|
||||
|
||||
- name: Check linting rules
|
||||
run: yarn lint
|
||||
run: pnpm lint
|
||||
|
||||
unit-tests:
|
||||
name: Unit tests
|
||||
|
@ -50,10 +53,10 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/setup-node
|
||||
- uses: ./.github/actions/yarn-install
|
||||
- uses: ./.github/actions/pnpm-install
|
||||
|
||||
- name: Run tests
|
||||
run: yarn test:unit
|
||||
run: pnpm test:unit
|
||||
|
||||
# Label of the container job
|
||||
integration-tests:
|
||||
|
@ -66,25 +69,28 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/setup-node
|
||||
- uses: ./.github/actions/yarn-install
|
||||
- uses: ./.github/actions/pnpm-install
|
||||
|
||||
- name: Generate Prisma Client
|
||||
run: pnpm db:generate
|
||||
|
||||
- name: Install system dependencies
|
||||
run: sudo apt-get update
|
||||
|
||||
- name: Install playwright dependencies
|
||||
run: yarn playwright install --with-deps chromium
|
||||
run: pnpm playwright install --with-deps chromium
|
||||
|
||||
- name: Create production build
|
||||
run: yarn turbo build:test --filter=@rallly/web
|
||||
run: pnpm turbo build:test --filter=@rallly/web
|
||||
|
||||
- name: Start services
|
||||
run: yarn docker:up
|
||||
run: pnpm docker:up
|
||||
|
||||
- name: Setup database
|
||||
run: yarn db:deploy
|
||||
run: pnpm db:deploy
|
||||
|
||||
- name: Run tests
|
||||
run: yarn turbo test:integration
|
||||
run: pnpm turbo test:integration
|
||||
|
||||
- name: Upload artifact playwright-report
|
||||
if: ${{ success() || failure() }}
|
||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -21,8 +21,6 @@ node_modules
|
|||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# local env files
|
||||
.env
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
1. Use yarn for package management
|
||||
1. Use pnpm for package management
|
||||
2. Use dayjs for date handling
|
||||
3. Use tailwindcss for styling
|
||||
4. Use react-query for data fetching
|
||||
|
|
10
README.md
10
README.md
|
@ -38,7 +38,7 @@ The following instructions are for running the project locally for development.
|
|||
2. Install dependencies
|
||||
|
||||
```bash
|
||||
yarn
|
||||
pnpm install
|
||||
```
|
||||
|
||||
3. Setup environment variables
|
||||
|
@ -54,7 +54,7 @@ The following instructions are for running the project locally for development.
|
|||
4. Generate Prisma client
|
||||
|
||||
```bash
|
||||
yarn db:generate
|
||||
pnpm db:generate
|
||||
```
|
||||
|
||||
5. Setup database
|
||||
|
@ -64,13 +64,13 @@ The following instructions are for running the project locally for development.
|
|||
To start the database, run:
|
||||
|
||||
```bash
|
||||
yarn docker:up
|
||||
pnpm docker:up
|
||||
```
|
||||
|
||||
Next run the following command to setup the database:
|
||||
|
||||
```bash
|
||||
yarn db:reset
|
||||
pnpm db:reset
|
||||
```
|
||||
|
||||
This will:
|
||||
|
@ -82,7 +82,7 @@ The following instructions are for running the project locally for development.
|
|||
6. Start the Next.js server
|
||||
|
||||
```bash
|
||||
yarn dev
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
## Contributors
|
||||
|
|
|
@ -13,7 +13,7 @@ To preview your changes locally, you can use the [mintlify cli](https://mintlify
|
|||
Install the cli globally:
|
||||
|
||||
```bash
|
||||
yarn global add mintlify
|
||||
pnpm install --global mintlify
|
||||
```
|
||||
|
||||
Navigate to this directory (where you can find `mint.json`):
|
||||
|
|
|
@ -3,6 +3,6 @@
|
|||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@rallly/tsconfig": "*"
|
||||
"@rallly/tsconfig": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,33 +12,42 @@
|
|||
"i18n:scan": "i18next-scanner --config i18next-scanner.config.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@rallly/billing": "*",
|
||||
"@rallly/icons": "*",
|
||||
"@rallly/languages": "*",
|
||||
"@rallly/tailwind-config": "*",
|
||||
"@rallly/ui": "*",
|
||||
"@rallly/utils": "*",
|
||||
"@prisma/client": "^6.4.1",
|
||||
"@rallly/billing": "workspace:*",
|
||||
"@rallly/database": "workspace:*",
|
||||
"@rallly/icons": "workspace:*",
|
||||
"@rallly/languages": "workspace:*",
|
||||
"@rallly/tailwind-config": "workspace:*",
|
||||
"@rallly/ui": "workspace:*",
|
||||
"@rallly/utils": "workspace:*",
|
||||
"@svgr/webpack": "^6.5.1",
|
||||
"@vercel/analytics": "^0.1.8",
|
||||
"dayjs": "^1.11.10",
|
||||
"dayjs": "^1.11.13",
|
||||
"gray-matter": "^4.0.3",
|
||||
"i18next": "^24.2.2",
|
||||
"i18next-icu": "^2.3.0",
|
||||
"i18next-resources-to-backend": "^1.2.1",
|
||||
"intl-messageformat": "^10.7.15",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.479.0",
|
||||
"motion": "^12.6.2",
|
||||
"nanoid": "^5.0.9",
|
||||
"next": "^14.2.25",
|
||||
"next-mdx-remote": "^5.0.0",
|
||||
"next-seo": "^6.1.0",
|
||||
"react-i18next": "^15.4.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-i18next": "^15.5.1",
|
||||
"react-use": "^17.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next/bundle-analyzer": "^12.3.4",
|
||||
"@rallly/eslint-config": "*",
|
||||
"@rallly/tsconfig": "*",
|
||||
"@next/bundle-analyzer": "^14.2.25",
|
||||
"@rallly/eslint-config": "workspace:*",
|
||||
"@rallly/tsconfig": "workspace:*",
|
||||
"@types/color-hash": "^1.0.2",
|
||||
"@types/lodash": "^4.14.178",
|
||||
"@types/react": "^18.2.0",
|
||||
"@types/react-dom": "^18.2.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"i18next-scanner": "^4.2.0",
|
||||
"i18next-scanner-typescript": "^1.1.1"
|
||||
|
|
|
@ -19,7 +19,10 @@ export async function middleware(request: NextRequest) {
|
|||
return;
|
||||
}
|
||||
|
||||
const locale = getPreferredLocale(request);
|
||||
const locale = getPreferredLocale({
|
||||
acceptLanguageHeader: request.headers.get("accept-language") ?? undefined,
|
||||
});
|
||||
|
||||
request.nextUrl.pathname = `/${locale}${pathname}`;
|
||||
|
||||
if (locale === "en") {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"installCommand": "yarn install",
|
||||
"buildCommand": "cd ../.. && yarn db:generate && yarn build:landing",
|
||||
"installCommand": "pnpm install",
|
||||
"buildCommand": "cd ../.. && pnpm db:generate && pnpm build:landing",
|
||||
"outputDirectory": ".next"
|
||||
}
|
||||
|
|
|
@ -1,22 +1,35 @@
|
|||
FROM node:20 AS builder
|
||||
# Base stage with Node.js 20 and Corepack enabled
|
||||
FROM node:20 AS base
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
RUN corepack enable
|
||||
|
||||
# Slim base stage with Node.js 20 and Corepack enabled
|
||||
FROM node:20-slim AS base-slim
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
RUN corepack enable
|
||||
|
||||
# --- Builder Stage ---
|
||||
FROM base AS builder
|
||||
WORKDIR /app
|
||||
RUN yarn global add turbo
|
||||
COPY package.json .
|
||||
RUN pnpm add -g turbo
|
||||
COPY . .
|
||||
RUN turbo prune --scope=@rallly/web --docker
|
||||
|
||||
FROM node:20 AS installer
|
||||
|
||||
# --- Installer Stage ---
|
||||
FROM base AS installer
|
||||
WORKDIR /app
|
||||
COPY .gitignore .gitignore
|
||||
COPY package.json .
|
||||
COPY --from=builder /app/out/json/ .
|
||||
COPY --from=builder /app/out/yarn.lock ./yarn.lock
|
||||
RUN yarn --network-timeout 1000000
|
||||
COPY --from=builder /app/out/pnpm-lock.yaml ./
|
||||
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
|
||||
|
||||
# Build the project
|
||||
COPY --from=builder /app/out/full/ .
|
||||
COPY turbo.json turbo.json
|
||||
RUN yarn db:generate
|
||||
RUN pnpm db:generate
|
||||
|
||||
ARG APP_VERSION
|
||||
ENV NEXT_PUBLIC_APP_VERSION=$APP_VERSION
|
||||
|
@ -24,11 +37,15 @@ ENV NEXT_PUBLIC_APP_VERSION=$APP_VERSION
|
|||
ARG SELF_HOSTED
|
||||
ENV NEXT_PUBLIC_SELF_HOSTED=$SELF_HOSTED
|
||||
|
||||
RUN SKIP_ENV_VALIDATION=1 yarn build
|
||||
RUN SKIP_ENV_VALIDATION=1 pnpm build
|
||||
|
||||
FROM node:20-slim AS runner
|
||||
# --- Runner Stage ---
|
||||
FROM base-slim AS runner
|
||||
|
||||
# prisma requirements
|
||||
# Disable Next.js telemetry for self-hosted instances
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
# Install required system packages for Prisma
|
||||
# (see https://www.prisma.io/docs/orm/reference/system-requirements)
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
|
@ -40,26 +57,36 @@ RUN apt-get update \
|
|||
|
||||
WORKDIR /app
|
||||
|
||||
RUN yarn global add prisma
|
||||
# Install prisma globally needed for runtime operations like migrations
|
||||
RUN pnpm add -g prisma
|
||||
|
||||
# Don't run production as root
|
||||
RUN addgroup --system --gid 1001 nodejs
|
||||
RUN adduser --system --uid 1001 nextjs
|
||||
# Set HOME env for non-root user
|
||||
ENV HOME=/app
|
||||
# Ensure /app is writable by nextjs user AND fix perms for global pnpm dir
|
||||
RUN chown -R nextjs:nodejs /app /pnpm
|
||||
|
||||
|
||||
USER nextjs
|
||||
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/scripts/docker-start.sh ./
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/packages/database/prisma ./prisma
|
||||
# Copy Corepack cache from installer stage to avoid runtime download
|
||||
COPY --from=installer /root/.cache/node/corepack/ /app/.cache/node/corepack/
|
||||
|
||||
# Copy app files
|
||||
COPY --from=builder /app/scripts/docker-start.sh ./
|
||||
COPY --from=builder /app/packages/database/prisma ./prisma
|
||||
COPY --from=installer /app/apps/web/next.config.js .
|
||||
COPY --from=installer /app/apps/web/package.json .
|
||||
|
||||
ENV PORT=3000
|
||||
EXPOSE 3000
|
||||
|
||||
# Automatically leverage output traces to reduce image size
|
||||
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
||||
COPY --from=installer --chown=nextjs:nodejs /app/apps/web/.next/standalone ./
|
||||
COPY --from=installer --chown=nextjs:nodejs /app/apps/web/.next/static ./apps/web/.next/static
|
||||
COPY --from=installer --chown=nextjs:nodejs /app/apps/web/public ./apps/web/public
|
||||
# Copy Next.js standalone output
|
||||
COPY --from=installer /app/apps/web/.next/standalone ./
|
||||
COPY --from=installer /app/apps/web/.next/static ./apps/web/.next/static
|
||||
COPY --from=installer /app/apps/web/public ./apps/web/public
|
||||
|
||||
ARG SELF_HOSTED
|
||||
ENV NEXT_PUBLIC_SELF_HOSTED=$SELF_HOSTED
|
||||
|
|
|
@ -8,10 +8,6 @@ const withBundleAnalyzer = require("@next/bundle-analyzer")({
|
|||
enabled: process.env.ANALYZE === "true",
|
||||
});
|
||||
|
||||
require("dotenv").config({
|
||||
path: "../../.env",
|
||||
});
|
||||
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
output:
|
||||
|
@ -100,9 +96,10 @@ const sentryWebpackPluginOptions = {
|
|||
};
|
||||
|
||||
const withBundleAnalyzerConfig = withBundleAnalyzer(nextConfig);
|
||||
|
||||
// Make sure adding Sentry options is the last code to run before exporting, to
|
||||
// ensure that your source maps include changes from all other Webpack plugins
|
||||
module.exports = withSentryConfig(
|
||||
withBundleAnalyzerConfig,
|
||||
sentryWebpackPluginOptions,
|
||||
);
|
||||
module.exports =
|
||||
process.env.NEXT_PUBLIC_SELF_HOSTED === "true"
|
||||
? withBundleAnalyzerConfig
|
||||
: withSentryConfig(withBundleAnalyzerConfig, sentryWebpackPluginOptions);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"dev": "dotenv -c development next dev",
|
||||
"build": "next build",
|
||||
"build:test": "NODE_ENV=test next build",
|
||||
"analyze": "cross-env ANALYZE=true next build",
|
||||
|
@ -13,7 +13,6 @@
|
|||
"i18n:scan": "i18next-scanner --config i18next-scanner.config.js",
|
||||
"test:integration": "NODE_ENV=test playwright test",
|
||||
"test:unit": "vitest run",
|
||||
"test": "yarn test:unit && yarn test:e2e",
|
||||
"test:codegen": "playwright codegen http://localhost:3000",
|
||||
"docker:start": "./scripts/docker-start.sh"
|
||||
},
|
||||
|
@ -23,20 +22,24 @@
|
|||
"@aws-sdk/client-s3": "^3.645.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.645.0",
|
||||
"@hookform/resolvers": "^3.3.1",
|
||||
"@next/bundle-analyzer": "^12.3.4",
|
||||
"@next/bundle-analyzer": "^14.2.25",
|
||||
"@next/env": "^15.3.1",
|
||||
"@panva/hkdf": "^1.2.1",
|
||||
"@prisma/client": "^6.4.1",
|
||||
"@radix-ui/react-radio-group": "^1.2.3",
|
||||
"@radix-ui/react-select": "^1.2.1",
|
||||
"@radix-ui/react-slot": "^1.1.2",
|
||||
"@radix-ui/react-switch": "^1.0.2",
|
||||
"@rallly/billing": "*",
|
||||
"@rallly/database": "*",
|
||||
"@rallly/emails": "*",
|
||||
"@rallly/icons": "*",
|
||||
"@rallly/languages": "*",
|
||||
"@rallly/posthog": "*",
|
||||
"@rallly/tailwind-config": "*",
|
||||
"@rallly/ui": "*",
|
||||
"@sentry/nextjs": "*",
|
||||
"@rallly/billing": "workspace:*",
|
||||
"@rallly/database": "workspace:*",
|
||||
"@rallly/emails": "workspace:*",
|
||||
"@rallly/icons": "workspace:*",
|
||||
"@rallly/languages": "workspace:*",
|
||||
"@rallly/posthog": "workspace:*",
|
||||
"@rallly/tailwind-config": "workspace:*",
|
||||
"@rallly/ui": "workspace:*",
|
||||
"@rallly/utils": "workspace:*",
|
||||
"@sentry/nextjs": "^8.49.0",
|
||||
"@svgr/webpack": "^6.5.1",
|
||||
"@t3-oss/env-nextjs": "^0.11.0",
|
||||
"@tanstack/react-query": "^4.0.0",
|
||||
|
@ -46,7 +49,7 @@
|
|||
"@trpc/server": "^10.13.0",
|
||||
"@upstash/qstash": "^2.7.17",
|
||||
"@upstash/ratelimit": "^1.2.1",
|
||||
"@vercel/functions": "^1.5.2",
|
||||
"@vercel/functions": "^2.0.0",
|
||||
"@vercel/kv": "^2.0.0",
|
||||
"ai": "^4.1.50",
|
||||
"autoprefixer": "^10.4.13",
|
||||
|
@ -55,7 +58,7 @@
|
|||
"color-hash": "^2.0.2",
|
||||
"cookie": "^0.7.0",
|
||||
"crypto": "^1.0.1",
|
||||
"dayjs": "^1.11.10",
|
||||
"dayjs": "^1.11.13",
|
||||
"i18next": "^24.2.2",
|
||||
"i18next-http-backend": "^3.0.2",
|
||||
"i18next-icu": "^2.3.0",
|
||||
|
@ -72,33 +75,42 @@
|
|||
"micro": "^10.0.1",
|
||||
"motion": "^12.6.2",
|
||||
"nanoid": "^5.0.9",
|
||||
"next": "^14.2.25",
|
||||
"next-auth": "^5.0.0-beta.25",
|
||||
"php-serialize": "^4.1.1",
|
||||
"postcss": "^8.4.31",
|
||||
"react": "^18.2.0",
|
||||
"react-big-calendar": "^1.8.1",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hook-form": "^7.42.1",
|
||||
"react-hook-form-persist": "^3.0.0",
|
||||
"react-i18next": "^15.4.1",
|
||||
"react-i18next": "^15.5.1",
|
||||
"react-remove-scroll": "^2.5.6",
|
||||
"react-use": "^17.4.0",
|
||||
"smoothscroll-polyfill": "^0.4.4",
|
||||
"spacetime": "^7.4.7",
|
||||
"superjson": "^2.0.0",
|
||||
"timezone-soft": "^1.5.1"
|
||||
"tailwindcss": "^3.4.17",
|
||||
"timezone-soft": "^1.5.1",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.26.10",
|
||||
"@playwright/test": "^1.49.1",
|
||||
"@rallly/eslint-config": "*",
|
||||
"@rallly/tsconfig": "*",
|
||||
"@rallly/eslint-config": "workspace:*",
|
||||
"@rallly/tsconfig": "workspace:*",
|
||||
"@types/color-hash": "^1.0.2",
|
||||
"@types/js-cookie": "^3.0.1",
|
||||
"@types/lodash": "^4.14.178",
|
||||
"@types/node": "^18.19.41",
|
||||
"@types/react": "^18.2.0",
|
||||
"@types/react-big-calendar": "^1.8.8",
|
||||
"@types/react-dom": "^18.2.0",
|
||||
"@types/smoothscroll-polyfill": "^0.3.1",
|
||||
"cheerio": "^1.0.0-rc.12",
|
||||
"cross-env": "^7.0.3",
|
||||
"i18next-scanner": "^4.2.0",
|
||||
"i18next-scanner-typescript": "^1.1.1",
|
||||
"vitest": "^2.1.9",
|
||||
"wait-on": "^6.0.1"
|
||||
"vitest": "^2.1.9"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Tile, TileGrid, TileTitle } from "@rallly/ui/tile";
|
||||
import Link from "next/link";
|
||||
|
||||
import type { Params } from "@/app/[locale]/types";
|
||||
import {
|
||||
|
@ -56,18 +57,22 @@ export default async function Page({ params }: { params: Params }) {
|
|||
<Trans i18nKey="homeNavTitle" defaults="Navigation" />
|
||||
</h2>
|
||||
<TileGrid>
|
||||
<Tile href="/polls">
|
||||
<Tile asChild>
|
||||
<Link href="/polls">
|
||||
<PollPageIcon />
|
||||
<TileTitle>
|
||||
<Trans i18nKey="polls" defaults="Polls" />
|
||||
</TileTitle>
|
||||
</Link>
|
||||
</Tile>
|
||||
|
||||
<Tile href="/events">
|
||||
<Tile asChild>
|
||||
<Link href="/events">
|
||||
<EventPageIcon />
|
||||
<TileTitle>
|
||||
<Trans i18nKey="events" defaults="Events" />
|
||||
</TileTitle>
|
||||
</Link>
|
||||
</Tile>
|
||||
|
||||
{/* <Tile href="/members">
|
||||
|
@ -84,25 +89,31 @@ export default async function Page({ params }: { params: Params }) {
|
|||
<Trans i18nKey="account" defaults="Account" />
|
||||
</h2>
|
||||
<TileGrid>
|
||||
<Tile href="/settings/profile">
|
||||
<Tile asChild>
|
||||
<Link href="/settings/profile">
|
||||
<ProfilePageIcon />
|
||||
<TileTitle>
|
||||
<Trans i18nKey="profile" defaults="Profile" />
|
||||
</TileTitle>
|
||||
</Link>
|
||||
</Tile>
|
||||
|
||||
<Tile href="/settings/preferences">
|
||||
<Tile asChild>
|
||||
<Link href="/settings/preferences">
|
||||
<PreferencesPageIcon />
|
||||
<TileTitle>
|
||||
<Trans i18nKey="preferences" defaults="Preferences" />
|
||||
</TileTitle>
|
||||
</Link>
|
||||
</Tile>
|
||||
|
||||
<Tile href="/settings/billing">
|
||||
<Tile asChild>
|
||||
<Link href="/settings/billing">
|
||||
<BillingPageIcon />
|
||||
<TileTitle>
|
||||
<Trans i18nKey="billing" defaults="Billing" />
|
||||
</TileTitle>
|
||||
</Link>
|
||||
</Tile>
|
||||
</TileGrid>
|
||||
</div>
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import "tailwindcss/tailwind.css";
|
||||
import "../../style.css";
|
||||
|
||||
import { defaultLocale, supportedLngs } from "@rallly/languages";
|
||||
import { PostHogProvider } from "@rallly/posthog/client";
|
||||
import { posthog, PostHogProvider } from "@rallly/posthog/client";
|
||||
import { Toaster } from "@rallly/ui/toaster";
|
||||
import { TooltipProvider } from "@rallly/ui/tooltip";
|
||||
import { domAnimation, LazyMotion } from "motion/react";
|
||||
|
@ -61,7 +60,7 @@ export default async function Root({
|
|||
<I18nProvider locale={locale}>
|
||||
<TRPCProvider>
|
||||
<LazyMotion features={domAnimation}>
|
||||
<PostHogProvider>
|
||||
<PostHogProvider client={posthog}>
|
||||
<PostHogPageView />
|
||||
<TooltipProvider>
|
||||
<UserProvider
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { withPosthog } from "@rallly/posthog/server";
|
||||
|
||||
import { handlers } from "@/next-auth";
|
||||
import { withPosthog } from "@/utils/posthog";
|
||||
|
||||
export const GET = withPosthog(handlers.GET);
|
||||
export const POST = withPosthog(handlers.POST);
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import type { Stripe } from "@rallly/billing";
|
||||
import { stripe } from "@rallly/billing";
|
||||
import { withPosthog } from "@rallly/posthog/server";
|
||||
import * as Sentry from "@sentry/nextjs";
|
||||
import type { NextRequest } from "next/server";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
import { withPosthog } from "@/utils/posthog";
|
||||
|
||||
import { getEventHandler } from "./handlers";
|
||||
|
||||
export const POST = withPosthog(async (request: NextRequest) => {
|
||||
|
|
|
@ -19,7 +19,9 @@ const handler = async (req: NextRequest) => {
|
|||
req,
|
||||
router: appRouter,
|
||||
createContext: async () => {
|
||||
const locale = getPreferredLocale(req);
|
||||
const locale = getPreferredLocale({
|
||||
acceptLanguageHeader: req.headers.get("accept-language") ?? undefined,
|
||||
});
|
||||
const user = session?.user
|
||||
? {
|
||||
id: session.user.id,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"use client";
|
||||
import { usePostHog } from "@rallly/posthog/client";
|
||||
import { usePathname, useSearchParams } from "next/navigation";
|
||||
import { usePostHog } from "posthog-js/react";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export function PostHogPageView() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import languages from "@rallly/languages";
|
||||
import { getPreferredLocale } from "@rallly/languages/get-preferred-locale";
|
||||
import { withPostHog } from "@rallly/posthog/next/middleware";
|
||||
import { getPosthogBootstrapCookie } from "@rallly/posthog/utils";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
import { withAuth } from "@/auth/edge";
|
||||
|
@ -19,7 +19,12 @@ export const middleware = withAuth(async (req) => {
|
|||
return NextResponse.redirect(newUrl);
|
||||
}
|
||||
|
||||
const locale = req.auth?.user?.locale || getPreferredLocale(req);
|
||||
const locale =
|
||||
req.auth?.user?.locale ||
|
||||
getPreferredLocale({
|
||||
acceptLanguageHeader: req.headers.get("accept-language") ?? undefined,
|
||||
});
|
||||
|
||||
if (supportedLocales.includes(locale)) {
|
||||
newUrl.pathname = `/${locale}${pathname}`;
|
||||
}
|
||||
|
@ -29,7 +34,12 @@ export const middleware = withAuth(async (req) => {
|
|||
res.headers.set("x-pathname", pathname);
|
||||
|
||||
if (req.auth?.user?.id) {
|
||||
await withPostHog(res, { distinctID: req.auth.user.id });
|
||||
const bootstrapCookie = getPosthogBootstrapCookie({
|
||||
distinctID: req.auth.user.id,
|
||||
});
|
||||
if (bootstrapCookie) {
|
||||
res.cookies.set(bootstrapCookie);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
|
|
15
apps/web/src/utils/posthog.ts
Normal file
15
apps/web/src/utils/posthog.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { posthog } from "@rallly/posthog/server";
|
||||
import { waitUntil } from "@vercel/functions";
|
||||
import type { NextRequest } from "next/server";
|
||||
|
||||
export function withPosthog(handler: (req: NextRequest) => Promise<Response>) {
|
||||
return async (req: NextRequest) => {
|
||||
const res = await handler(req);
|
||||
try {
|
||||
waitUntil(Promise.all([posthog?.shutdown()]));
|
||||
} catch (error) {
|
||||
console.error("Failed to flush PostHog events:", error);
|
||||
}
|
||||
return res;
|
||||
};
|
||||
}
|
|
@ -3,10 +3,15 @@
|
|||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
},
|
||||
"strictNullChecks": true,
|
||||
"types": ["vitest/globals"]
|
||||
"types": [
|
||||
"vitest/globals"
|
||||
],
|
||||
"target": "ES2017"
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
|
@ -15,5 +20,10 @@
|
|||
".next/types/**/*.ts",
|
||||
"vitest.config.mts"
|
||||
],
|
||||
"exclude": ["node_modules", ".next/**/*", "playwright-report", "test-results"]
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
".next/**/*",
|
||||
"playwright-report",
|
||||
"test-results"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"installCommand": "yarn install",
|
||||
"buildCommand": "cd ../.. && yarn db:generate && yarn build:web && yarn db:deploy",
|
||||
"installCommand": "pnpm install",
|
||||
"buildCommand": "cd ../.. && pnpm db:generate && pnpm build:web && pnpm db:deploy",
|
||||
"outputDirectory": ".next"
|
||||
}
|
||||
|
|
27
package.json
27
package.json
|
@ -17,7 +17,7 @@
|
|||
"db:migrate": "prisma migrate dev",
|
||||
"db:reset": "prisma migrate reset",
|
||||
"db:push": "prisma db push",
|
||||
"docker:up": "docker compose -f docker-compose.dev.yml up -d && wait-on --timeout 60000 tcp:localhost:5450",
|
||||
"docker:up": "docker compose -f docker-compose.dev.yml up -d && pnpm dlx wait-on --timeout 60000 tcp:localhost:5450",
|
||||
"docker:down": "docker compose -f docker-compose.dev.yml down --volumes --remove-orphans",
|
||||
"test:integration": "turbo test:integration",
|
||||
"test:unit": "turbo test:unit",
|
||||
|
@ -30,33 +30,22 @@
|
|||
"sherif:fix": "npx sherif@latest --fix"
|
||||
},
|
||||
"prisma": {
|
||||
"seed": "yarn workspace @rallly/database db:seed",
|
||||
"seed": "pnpm --filter @rallly/database db:seed",
|
||||
"schema": "./packages/database/prisma/schema.prisma"
|
||||
},
|
||||
"workspaces": [
|
||||
"apps/*",
|
||||
"packages/*"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@prisma/client": "^6.4.1",
|
||||
"@sentry/nextjs": "^8.49.0",
|
||||
"@types/react": "^18.2.48",
|
||||
"@types/react-dom": "^18.2.18",
|
||||
"dotenv-cli": "^7.1.0",
|
||||
"next": "^14.2.25",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"@playwright/test": "^1.49.1",
|
||||
"dotenv-cli": "^8.0.0",
|
||||
"eslint": "^8.52.0",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier-plugin-tailwindcss": "^0.6.8",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"prisma": "^6.4.1",
|
||||
"turbo": "^2.4.4",
|
||||
"typescript": "^5.8.2",
|
||||
"vitest": "^2.1.9",
|
||||
"zod": "^3.23.8"
|
||||
"vitest": "^2.1.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": "20.x"
|
||||
},
|
||||
"packageManager": "yarn@1.22.22"
|
||||
"packageManager": "pnpm@10.9.0"
|
||||
}
|
||||
|
|
|
@ -15,11 +15,12 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-radio-group": "^1.2.3",
|
||||
"@rallly/ui": "*",
|
||||
"next": "*",
|
||||
"@rallly/database": "workspace:*",
|
||||
"@rallly/ui": "workspace:*",
|
||||
"stripe": "^13.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rallly/eslint-config": "*"
|
||||
"@rallly/eslint-config": "workspace:*",
|
||||
"@rallly/tsconfig": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,11 +11,15 @@
|
|||
"type-check": "tsc --pretty --noEmit"
|
||||
},
|
||||
"exports": "./index.ts",
|
||||
"dependencies": {
|
||||
"@prisma/client": "^6.4.1",
|
||||
"dayjs": "^1.11.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@faker-js/faker": "^7.6.0",
|
||||
"@rallly/eslint-config": "*",
|
||||
"@rallly/tsconfig": "*",
|
||||
"@types/node": "^18.15.10",
|
||||
"@rallly/eslint-config": "workspace:*",
|
||||
"@rallly/tsconfig": "workspace:*",
|
||||
"@types/node": "^18.19.41",
|
||||
"prisma": "^6.4.1",
|
||||
"tsx": "^4.6.2"
|
||||
}
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@prisma/client@^4.10.1":
|
||||
version "4.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-4.10.1.tgz#c47fd54661ee74b174cee63e9dc418ecf57a6ccd"
|
||||
integrity sha512-VonXLJZybdt8e5XZH5vnIGCRNnIh6OMX1FS3H/yzMGLT3STj5TJ/OkMcednrvELgk8PK89Vo3aSh51MWNO0axA==
|
||||
dependencies:
|
||||
"@prisma/engines-version" "4.10.1-2.aead147aa326ccb985dcfed5b065b4fdabd44b19"
|
||||
|
||||
"@prisma/engines-version@4.10.1-2.aead147aa326ccb985dcfed5b065b4fdabd44b19":
|
||||
version "4.10.1-2.aead147aa326ccb985dcfed5b065b4fdabd44b19"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-4.10.1-2.aead147aa326ccb985dcfed5b065b4fdabd44b19.tgz#312359d9d00e39e323136d0270876293d315658e"
|
||||
integrity sha512-tsjTho7laDhf9EJ9EnDxAPEf7yrigSMDhniXeU4YoWc7azHAs4GPxRi2P9LTFonmHkJLMOLjR77J1oIP8Ife1w==
|
||||
|
||||
"@prisma/engines@4.10.1":
|
||||
version "4.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-4.10.1.tgz#c7062747f254e5d5fce98a8cae566c25f9f29fb2"
|
||||
integrity sha512-B3tcTxjx196nuAu1GOTKO9cGPUgTFHYRdkPkTS4m5ptb2cejyBlH9X7GOfSt3xlI7p4zAJDshJP4JJivCg9ouA==
|
||||
|
||||
prisma@^4.10.1:
|
||||
version "4.10.1"
|
||||
resolved "https://registry.yarnpkg.com/prisma/-/prisma-4.10.1.tgz#88084695d7b364ae6bebf93d5006f84439c4e7d1"
|
||||
integrity sha512-0jDxgg+DruB1kHVNlcspXQB9au62IFfVg9drkhzXudszHNUAQn0lVuu+T8np0uC2z1nKD5S3qPeCyR8u5YFLnA==
|
||||
dependencies:
|
||||
"@prisma/engines" "4.10.1"
|
|
@ -16,15 +16,21 @@
|
|||
"@aws-sdk/client-ses": "^3.501.0",
|
||||
"@aws-sdk/credential-provider-node": "^3.501.0",
|
||||
"@react-email/components": "^0.0.14",
|
||||
"@react-email/render": "^0.0.12",
|
||||
"@vercel/functions": "*",
|
||||
"@react-email/render": "^1.0.6",
|
||||
"@vercel/functions": "^2.0.0",
|
||||
"i18next": "^24.2.2",
|
||||
"i18next-icu": "^2.3.0",
|
||||
"i18next-resources-to-backend": "^1.2.1",
|
||||
"nodemailer": "^6.9.9",
|
||||
"react-email": "^4.0.2"
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-email": "^4.0.2",
|
||||
"react-i18next": "^15.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rallly/tailwind-config": "*",
|
||||
"@rallly/tsconfig": "*",
|
||||
"@rallly/utils": "*",
|
||||
"@rallly/tailwind-config": "workspace:*",
|
||||
"@rallly/tsconfig": "workspace:*",
|
||||
"@rallly/utils": "workspace:*",
|
||||
"@types/nodemailer": "^6.4.14"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
# React Email Starter
|
||||
|
||||
A live preview right in your browser so you don't need to keep sending real emails during development.
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, install the dependencies:
|
||||
|
||||
```sh
|
||||
npm install
|
||||
# or
|
||||
yarn
|
||||
```
|
||||
|
||||
Then, run the development server:
|
||||
|
||||
```sh
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
```
|
||||
|
||||
Open [localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
## License
|
||||
|
||||
MIT License
|
|
@ -1,4 +1,4 @@
|
|||
import { Section } from "@react-email/section";
|
||||
import { Section } from "@react-email/components";
|
||||
import { Trans } from "react-i18next/TransWithoutContext";
|
||||
|
||||
import type { EmailContext } from "../types";
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
import { Client } from "@upstash/qstash";
|
||||
|
||||
export function createQstashClient() {
|
||||
if (!process.env.QSTASH_TOKEN) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Client({
|
||||
token: process.env.QSTASH_TOKEN,
|
||||
});
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import { Section } from "@react-email/section";
|
||||
import { Section } from "@react-email/components";
|
||||
import { Trans } from "react-i18next/TransWithoutContext";
|
||||
|
||||
import { EmailLayout } from "../components/email-layout";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Section } from "@react-email/section";
|
||||
import { Section } from "@react-email/components";
|
||||
import { Trans } from "react-i18next/TransWithoutContext";
|
||||
|
||||
import { EmailLayout } from "../components/email-layout";
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -8,7 +8,6 @@
|
|||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^8.28.0",
|
||||
"@typescript-eslint/parser": "^8.28.0",
|
||||
"eslint": "^8.52.0",
|
||||
"eslint-config-next": "^14.0.1",
|
||||
"eslint-config-turbo": "^2.0.3",
|
||||
"eslint-import-resolver-typescript": "^2.7.0",
|
||||
|
|
|
@ -7,5 +7,9 @@
|
|||
"dependencies": {
|
||||
"@heroicons/react": "^1.0.6",
|
||||
"lucide-react": "^0.479.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
"negotiator": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rallly/tsconfig": "workspace:*",
|
||||
"@types/negotiator": "^0.6.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
import languages, { defaultLocale } from "./index";
|
||||
import Negotiator from "negotiator";
|
||||
import { match } from "@formatjs/intl-localematcher";
|
||||
import type { NextRequest } from "next/server";
|
||||
|
||||
const locales = Object.keys(languages);
|
||||
|
||||
export function getPreferredLocale(req: NextRequest) {
|
||||
export function getPreferredLocale({
|
||||
acceptLanguageHeader,
|
||||
}: {
|
||||
acceptLanguageHeader?: string;
|
||||
}) {
|
||||
if (!acceptLanguageHeader) {
|
||||
return defaultLocale;
|
||||
}
|
||||
|
||||
const preferredLanguages = new Negotiator({
|
||||
headers: {
|
||||
"accept-language": req.headers.get("accept-language") ?? "",
|
||||
"accept-language": acceptLanguageHeader,
|
||||
},
|
||||
})
|
||||
.languages()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"extends": "@rallly/tsconfig/react.json",
|
||||
"include": ["**/*.ts"],
|
||||
"extends": "@rallly/tsconfig/node.json",
|
||||
"include": ["src/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
|
|
@ -4,23 +4,21 @@
|
|||
"private": true,
|
||||
"exports": {
|
||||
"./server": "./src/server/index.ts",
|
||||
"./client": "./src/client/index.ts",
|
||||
"./next/middleware": "./src/next/middleware.ts"
|
||||
"./client": "./src/client.ts",
|
||||
"./utils": "./src/utils.ts"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint ./src",
|
||||
"type-check": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"js-cookie": "^3.0.1",
|
||||
"posthog-js": "^1.234.1",
|
||||
"posthog-node": "^4.10.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rallly/eslint-config": "*",
|
||||
"@rallly/tsconfig": "*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"next": "^14.2.13",
|
||||
"react": "^18.2.0"
|
||||
"@rallly/eslint-config": "workspace:*",
|
||||
"@rallly/tsconfig": "workspace:*",
|
||||
"@types/js-cookie": "^3.0.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
"use client";
|
||||
import Cookies from "js-cookie";
|
||||
import posthog from "posthog-js";
|
||||
import { PostHogProvider as Provider } from "posthog-js/react";
|
||||
import React from "react";
|
||||
|
||||
import { POSTHOG_BOOTSTAP_DATA_COOKIE_NAME } from "../constants";
|
||||
import { POSTHOG_BOOTSTAP_DATA_COOKIE_NAME } from "./constants";
|
||||
|
||||
export { PostHogProvider, usePostHog } from "posthog-js/react";
|
||||
|
||||
if (typeof window !== "undefined" && process.env.NEXT_PUBLIC_POSTHOG_API_KEY) {
|
||||
let bootstrapData = {};
|
||||
|
@ -31,6 +31,4 @@ if (typeof window !== "undefined" && process.env.NEXT_PUBLIC_POSTHOG_API_KEY) {
|
|||
});
|
||||
}
|
||||
|
||||
export function PostHogProvider(props: { children?: React.ReactNode }) {
|
||||
return <Provider client={posthog}>{props.children}</Provider>;
|
||||
}
|
||||
export { posthog };
|
|
@ -1,4 +0,0 @@
|
|||
"use client";
|
||||
|
||||
export { PostHogProvider } from "./provider";
|
||||
export { usePostHog } from "posthog-js/react";
|
|
@ -1,23 +0,0 @@
|
|||
import type { NextResponse } from "next/server";
|
||||
|
||||
import { POSTHOG_BOOTSTAP_DATA_COOKIE_NAME } from "../constants";
|
||||
|
||||
const posthogApiKey = process.env.NEXT_PUBLIC_POSTHOG_API_KEY;
|
||||
|
||||
export async function withPostHog(
|
||||
res: NextResponse,
|
||||
bootstrapData: { distinctID?: string },
|
||||
) {
|
||||
if (!posthogApiKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
res.cookies.set({
|
||||
name: POSTHOG_BOOTSTAP_DATA_COOKIE_NAME,
|
||||
value: JSON.stringify(bootstrapData),
|
||||
httpOnly: false,
|
||||
secure: true,
|
||||
sameSite: "lax",
|
||||
path: "/",
|
||||
});
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
import { waitUntil } from "@vercel/functions";
|
||||
import type { NextRequest } from "next/server";
|
||||
import { PostHog } from "posthog-node";
|
||||
|
||||
function PostHogClient() {
|
||||
|
@ -14,15 +12,3 @@ function PostHogClient() {
|
|||
}
|
||||
|
||||
export const posthog = PostHogClient();
|
||||
|
||||
export function withPosthog(handler: (req: NextRequest) => Promise<Response>) {
|
||||
return async (req: NextRequest) => {
|
||||
const res = await handler(req);
|
||||
try {
|
||||
waitUntil(Promise.all([posthog?.shutdown()]));
|
||||
} catch (error) {
|
||||
console.error("Failed to flush PostHog events:", error);
|
||||
}
|
||||
return res;
|
||||
};
|
||||
}
|
||||
|
|
20
packages/posthog/src/utils.ts
Normal file
20
packages/posthog/src/utils.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { POSTHOG_BOOTSTAP_DATA_COOKIE_NAME } from "./constants";
|
||||
|
||||
const posthogApiKey = process.env.NEXT_PUBLIC_POSTHOG_API_KEY;
|
||||
|
||||
export function getPosthogBootstrapCookie(bootstrapData: {
|
||||
distinctID?: string;
|
||||
}) {
|
||||
if (!posthogApiKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
name: POSTHOG_BOOTSTAP_DATA_COOKIE_NAME,
|
||||
value: JSON.stringify(bootstrapData),
|
||||
httpOnly: false,
|
||||
secure: true,
|
||||
sameSite: "lax" as const,
|
||||
path: "/",
|
||||
};
|
||||
}
|
|
@ -4,6 +4,9 @@
|
|||
"private": true,
|
||||
"main": "tailwind.config.js",
|
||||
"types": "tailwind.config.d.ts",
|
||||
"dependencies": {
|
||||
"tailwindcss": "^3.4.17"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/typography": "^0.5.13",
|
||||
"autoprefixer": "^10.4.13",
|
||||
|
|
15
packages/tsconfig/node.json
Normal file
15
packages/tsconfig/node.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"display": "Node.js",
|
||||
"compilerOptions": {
|
||||
"lib": ["es2020"],
|
||||
"module": "NodeNext",
|
||||
"target": "es2020",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"moduleResolution": "NodeNext",
|
||||
"noUncheckedIndexedAccess": true
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@
|
|||
"@radix-ui/react-dropdown-menu": "^2.0.4",
|
||||
"@radix-ui/react-label": "^2.0.1",
|
||||
"@radix-ui/react-popover": "^1.0.5",
|
||||
"@radix-ui/react-portal": "^1.1.6",
|
||||
"@radix-ui/react-progress": "^1.1.2",
|
||||
"@radix-ui/react-radio-group": "^1.2.3",
|
||||
"@radix-ui/react-select": "^1.2.1",
|
||||
|
@ -33,17 +34,22 @@
|
|||
"@radix-ui/react-tabs": "^1.0.4",
|
||||
"@radix-ui/react-toast": "^1.1.4",
|
||||
"@radix-ui/react-tooltip": "^1.1.8",
|
||||
"@rallly/icons": "*",
|
||||
"@rallly/languages": "*",
|
||||
"@rallly/tailwind-config": "*",
|
||||
"@rallly/icons": "workspace:*",
|
||||
"@rallly/languages": "workspace:*",
|
||||
"@rallly/tailwind-config": "workspace:*",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^1.2.1",
|
||||
"cmdk": "^0.2.1",
|
||||
"lucide-react": "^0.479.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hook-form": "^7.42.1",
|
||||
"tailwind-merge": "^1.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rallly/eslint-config": "*",
|
||||
"@rallly/tsconfig": "*"
|
||||
"@rallly/eslint-config": "workspace:*",
|
||||
"@rallly/tsconfig": "workspace:*",
|
||||
"@types/react": "^18.2.0",
|
||||
"@types/react-dom": "^18.2.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,21 @@
|
|||
"use client";
|
||||
|
||||
import { Slot } from "@radix-ui/react-slot";
|
||||
import Link from "next/link";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "./lib/utils";
|
||||
|
||||
const Tile = React.forwardRef<
|
||||
HTMLAnchorElement,
|
||||
React.ComponentPropsWithoutRef<typeof Link>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<Link
|
||||
HTMLDivElement,
|
||||
{
|
||||
className?: string;
|
||||
children?: React.ReactNode;
|
||||
asChild?: boolean;
|
||||
}
|
||||
>(({ className, asChild, children, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "div";
|
||||
return (
|
||||
<Comp
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"text-card-foreground bg-background flex flex-col justify-end rounded-xl border p-3 shadow-sm transition-shadow hover:bg-gray-50 active:shadow-none",
|
||||
|
@ -19,8 +24,9 @@ const Tile = React.forwardRef<
|
|||
{...props}
|
||||
>
|
||||
{children}
|
||||
</Link>
|
||||
));
|
||||
</Comp>
|
||||
);
|
||||
});
|
||||
Tile.displayName = "Tile";
|
||||
|
||||
const TileIcon = React.forwardRef<
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
"nanoid": "^5.0.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rallly/tsconfig": "workspace:*",
|
||||
"@types/node": "^18.19.41",
|
||||
"vitest": "^2.1.9"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"types": ["vitest/globals"]
|
||||
"types": ["vitest/globals", "node"],
|
||||
"lib": ["es2020", "dom"]
|
||||
},
|
||||
"extends": "@rallly/tsconfig/react.json",
|
||||
"include": ["**/*.ts", "**/*.tsx"]
|
||||
"extends": "@rallly/tsconfig/node.json",
|
||||
"include": ["**/*.ts"]
|
||||
}
|
||||
|
|
17428
pnpm-lock.yaml
generated
Normal file
17428
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load diff
3
pnpm-workspace.yaml
Normal file
3
pnpm-workspace.yaml
Normal file
|
@ -0,0 +1,3 @@
|
|||
packages:
|
||||
- 'apps/*'
|
||||
- 'packages/*'
|
|
@ -4,5 +4,5 @@ set -e
|
|||
export DIRECT_DATABASE_URL=$DATABASE_URL
|
||||
export AUTH_URL=$NEXT_PUBLIC_BASE_URL
|
||||
|
||||
prisma migrate deploy --schema=./prisma/schema.prisma
|
||||
pnpm prisma migrate deploy --schema=./prisma/schema.prisma
|
||||
node apps/web/server.js
|
||||
|
|
Loading…
Add table
Reference in a new issue