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