mirror of
https://github.com/lukevella/rallly.git
synced 2025-06-06 20:51:48 +02:00
Replace eslint with biome
This commit is contained in:
parent
251e517810
commit
cfb9ec8e8a
183 changed files with 422 additions and 409 deletions
9
.github/workflows/ci.yml
vendored
9
.github/workflows/ci.yml
vendored
|
@ -24,15 +24,18 @@ jobs:
|
||||||
run: pnpm type-check
|
run: pnpm type-check
|
||||||
|
|
||||||
linting:
|
linting:
|
||||||
name: Linting
|
name: Linting and Formatting
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: ./.github/actions/setup-node
|
- uses: ./.github/actions/setup-node
|
||||||
- uses: ./.github/actions/pnpm-install
|
- uses: ./.github/actions/pnpm-install
|
||||||
|
|
||||||
- name: Check linting rules
|
- name: Install Biome
|
||||||
run: pnpm lint
|
run: pnpm add -D @biomejs/biome
|
||||||
|
|
||||||
|
- name: Check linting and formatting
|
||||||
|
run: pnpm ci
|
||||||
|
|
||||||
unit-tests:
|
unit-tests:
|
||||||
name: Unit tests
|
name: Unit tests
|
||||||
|
|
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
|
@ -1,7 +1,10 @@
|
||||||
{
|
{
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.fixAll": "explicit"
|
"source.fixAll.eslint": "never",
|
||||||
|
"source.organizeImports.biome": "explicit",
|
||||||
|
"quickfix.biome": "explicit"
|
||||||
},
|
},
|
||||||
|
"editor.defaultFormatter": "biomejs.biome",
|
||||||
"typescript.tsdk": "node_modules/typescript/lib",
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
"typescript.preferences.importModuleSpecifier": "non-relative",
|
"typescript.preferences.importModuleSpecifier": "non-relative",
|
||||||
"cSpell.words": ["Rallly", "Vella"]
|
"cSpell.words": ["Rallly", "Vella"]
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
/** @type {import("eslint").Linter.Config} */
|
|
||||||
module.exports = {
|
|
||||||
...require("@rallly/eslint-config")(__dirname),
|
|
||||||
};
|
|
|
@ -1,4 +0,0 @@
|
||||||
/** @type {import("eslint").Linter.Config} */
|
|
||||||
module.exports = {
|
|
||||||
...require("@rallly/eslint-config")(__dirname),
|
|
||||||
};
|
|
8
apps/landing/declarations/i18next.d.ts
vendored
8
apps/landing/declarations/i18next.d.ts
vendored
|
@ -1,9 +1,9 @@
|
||||||
import "react-i18next";
|
import "react-i18next";
|
||||||
|
|
||||||
import blog from "../public/locales/en/blog.json";
|
import type blog from "../public/locales/en/blog.json";
|
||||||
import common from "../public/locales/en/common.json";
|
import type common from "../public/locales/en/common.json";
|
||||||
import home from "../public/locales/en/home.json";
|
import type home from "../public/locales/en/home.json";
|
||||||
import pricing from "../public/locales/en/pricing.json";
|
import type pricing from "../public/locales/en/pricing.json";
|
||||||
|
|
||||||
interface I18nNamespaces {
|
interface I18nNamespaces {
|
||||||
common: typeof common;
|
common: typeof common;
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"analyze": "cross-env ANALYZE=true next build",
|
"analyze": "cross-env ANALYZE=true next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "eslint .",
|
|
||||||
"type-check": "tsc --pretty --noEmit",
|
"type-check": "tsc --pretty --noEmit",
|
||||||
"i18n:scan": "i18next-scanner --config i18next-scanner.config.js",
|
"i18n:scan": "i18next-scanner --config i18next-scanner.config.js",
|
||||||
"prettier": "prettier --write ./src"
|
"prettier": "prettier --write ./src"
|
||||||
|
@ -39,7 +38,6 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@next/bundle-analyzer": "^12.3.4",
|
"@next/bundle-analyzer": "^12.3.4",
|
||||||
"@rallly/eslint-config": "workspace:*",
|
|
||||||
"@rallly/tsconfig": "workspace:*",
|
"@rallly/tsconfig": "workspace:*",
|
||||||
"@types/accept-language-parser": "^1.5.3",
|
"@types/accept-language-parser": "^1.5.3",
|
||||||
"@types/color-hash": "^1.0.2",
|
"@types/color-hash": "^1.0.2",
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
(function (w, d, e, u, f, l, n) {
|
((w, d, e, u, f, l, n) => {
|
||||||
(w[f] =
|
(w[f] =
|
||||||
w[f] ||
|
w[f] ||
|
||||||
function () {
|
(() => {
|
||||||
(w[f].q = w[f].q || []).push(arguments);
|
(w[f].q = w[f].q || []).push(arguments);
|
||||||
}),
|
})),
|
||||||
(l = d.createElement(e)),
|
(l = d.createElement(e)),
|
||||||
(l.async = 1),
|
(l.async = 1),
|
||||||
(l.src = u),
|
(l.src = u),
|
||||||
|
|
|
@ -19,7 +19,7 @@ import {
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { usePathname, useRouter } from "next/navigation";
|
import { usePathname, useRouter } from "next/navigation";
|
||||||
import * as React from "react";
|
import type * as React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import { Trans } from "@/components/trans";
|
import { Trans } from "@/components/trans";
|
||||||
|
@ -302,7 +302,7 @@ export const Footer: React.FunctionComponent = () => {
|
||||||
<a
|
<a
|
||||||
target="_blank"
|
target="_blank"
|
||||||
href="https://vercel.com?utm_source=rallly&utm_campaign=oss"
|
href="https://vercel.com?utm_source=rallly&utm_campaign=oss"
|
||||||
className="inline-block text-white"
|
className="inline-block text-white" rel="noreferrer"
|
||||||
>
|
>
|
||||||
<Image
|
<Image
|
||||||
src="/static/images/partners/vercel-logotype-dark.svg"
|
src="/static/images/partners/vercel-logotype-dark.svg"
|
||||||
|
@ -316,7 +316,7 @@ export const Footer: React.FunctionComponent = () => {
|
||||||
<a
|
<a
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className="inline-block"
|
className="inline-block"
|
||||||
href="/partners/digitalocean"
|
href="/partners/digitalocean" rel="noreferrer"
|
||||||
>
|
>
|
||||||
<Image
|
<Image
|
||||||
src="/static/images/partners/digitalocean-logo.svg"
|
src="/static/images/partners/digitalocean-logo.svg"
|
||||||
|
@ -330,7 +330,7 @@ export const Footer: React.FunctionComponent = () => {
|
||||||
<a
|
<a
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className="inline-block"
|
className="inline-block"
|
||||||
href="https://sentry.io"
|
href="https://sentry.io" rel="noreferrer"
|
||||||
>
|
>
|
||||||
<Image
|
<Image
|
||||||
src="/static/images/partners/sentry.svg"
|
src="/static/images/partners/sentry.svg"
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
} from "@rallly/ui/dropdown-menu";
|
} from "@rallly/ui/dropdown-menu";
|
||||||
import { Analytics } from "@vercel/analytics/react";
|
import { Analytics } from "@vercel/analytics/react";
|
||||||
import { ChevronRightIcon, MenuIcon } from "lucide-react";
|
import { ChevronRightIcon, MenuIcon } from "lucide-react";
|
||||||
import { Viewport } from "next";
|
import type { Viewport } from "next";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { Trans } from "react-i18next/TransWithoutContext";
|
import { Trans } from "react-i18next/TransWithoutContext";
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { TFunction } from "i18next";
|
import type { TFunction } from "i18next";
|
||||||
import { TrendingUpIcon } from "lucide-react";
|
import { TrendingUpIcon } from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { Trans } from "react-i18next/TransWithoutContext";
|
import { Trans } from "react-i18next/TransWithoutContext";
|
||||||
|
|
|
@ -7,7 +7,8 @@ type Props = {
|
||||||
const PostBody = ({ content }: Props) => {
|
const PostBody = ({ content }: Props) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={markdownStyles["markdown"]}
|
className={markdownStyles.markdown}
|
||||||
|
// biome-ignore lint/security/noDangerouslySetInnerHtml: <explanation>
|
||||||
dangerouslySetInnerHTML={{ __html: content }}
|
dangerouslySetInnerHTML={{ __html: content }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { Button } from "@rallly/ui/button";
|
||||||
import { FileSearchIcon } from "lucide-react";
|
import { FileSearchIcon } from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
import * as React from "react";
|
import type * as React from "react";
|
||||||
|
|
||||||
export interface ComponentProps {
|
export interface ComponentProps {
|
||||||
icon?: React.ReactNode;
|
icon?: React.ReactNode;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { prisma } from "@rallly/database";
|
import { prisma } from "@rallly/database";
|
||||||
import { TFunction } from "i18next";
|
import type { TFunction } from "i18next";
|
||||||
import {
|
import {
|
||||||
CalendarCheck2Icon,
|
CalendarCheck2Icon,
|
||||||
LanguagesIcon,
|
LanguagesIcon,
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { motion } from "framer-motion";
|
||||||
import { ArrowUpRight } from "lucide-react";
|
import { ArrowUpRight } from "lucide-react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import React from "react";
|
import type React from "react";
|
||||||
|
|
||||||
import { Trans } from "@/components/trans";
|
import { Trans } from "@/components/trans";
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
"use client";
|
"use client";
|
||||||
import i18next, { Namespace } from "i18next";
|
import i18next, { type Namespace } from "i18next";
|
||||||
import ICU from "i18next-icu";
|
import ICU from "i18next-icu";
|
||||||
import resourcesToBackend from "i18next-resources-to-backend";
|
import resourcesToBackend from "i18next-resources-to-backend";
|
||||||
import React from "react";
|
import type React from "react";
|
||||||
import {
|
import {
|
||||||
I18nextProvider,
|
I18nextProvider,
|
||||||
initReactI18next,
|
initReactI18next,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { createInstance, Namespace } from "i18next";
|
import { createInstance, type Namespace } from "i18next";
|
||||||
import ICU from "i18next-icu";
|
import ICU from "i18next-icu";
|
||||||
import resourcesToBackend from "i18next-resources-to-backend";
|
import resourcesToBackend from "i18next-resources-to-backend";
|
||||||
import { initReactI18next } from "react-i18next/initReactI18next";
|
import { initReactI18next } from "react-i18next/initReactI18next";
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import allLanguages from "@rallly/languages";
|
import allLanguages from "@rallly/languages";
|
||||||
import { InitOptions } from "i18next";
|
import type { InitOptions } from "i18next";
|
||||||
|
|
||||||
export const fallbackLng = "en";
|
export const fallbackLng = "en";
|
||||||
export const languages = Object.keys(allLanguages);
|
export const languages = Object.keys(allLanguages);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { supportedLngs } from "@rallly/languages";
|
import { supportedLngs } from "@rallly/languages";
|
||||||
import languageParser from "accept-language-parser";
|
import languageParser from "accept-language-parser";
|
||||||
import { NextRequest, NextResponse } from "next/server";
|
import { type NextRequest, NextResponse } from "next/server";
|
||||||
|
|
||||||
export async function getLocaleFromHeader(req: NextRequest) {
|
export async function getLocaleFromHeader(req: NextRequest) {
|
||||||
const headers = req.headers;
|
const headers = req.headers;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* eslint-disable @next/next/no-img-element */
|
|
||||||
import { ImageResponse } from "next/og";
|
import { ImageResponse } from "next/og";
|
||||||
import { NextRequest } from "next/server";
|
import type { NextRequest } from "next/server";
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
runtime: "edge",
|
runtime: "edge",
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { NextPage } from "next";
|
import type React from "react";
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
export type ReactTag = keyof JSX.IntrinsicElements;
|
export type ReactTag = keyof JSX.IntrinsicElements;
|
||||||
|
|
||||||
|
@ -7,19 +6,6 @@ export type PropsOf<TTag extends ReactTag> = TTag extends React.ElementType
|
||||||
? React.ComponentProps<TTag>
|
? React.ComponentProps<TTag>
|
||||||
: never;
|
: never;
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
||||||
export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
|
|
||||||
getLayout?: (page: React.ReactElement) => React.ReactNode;
|
|
||||||
};
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
||||||
export type PropsWithClassName<TProps extends Record<string, unknown> = {}> =
|
|
||||||
React.PropsWithChildren<TProps> & {
|
|
||||||
className?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type IconComponent = React.ComponentType<PropsWithClassName>;
|
|
||||||
|
|
||||||
export type Post = {
|
export type Post = {
|
||||||
slug: string;
|
slug: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
/** @type {import("eslint").Linter.Config} */
|
|
||||||
module.exports = {
|
|
||||||
...require("@rallly/eslint-config")(__dirname),
|
|
||||||
};
|
|
4
apps/web/declarations/i18next.d.ts
vendored
4
apps/web/declarations/i18next.d.ts
vendored
|
@ -1,8 +1,8 @@
|
||||||
import "i18next";
|
import "i18next";
|
||||||
|
|
||||||
import emails from "@rallly/emails/locales/emails.json";
|
import type emails from "@rallly/emails/locales/emails.json";
|
||||||
|
|
||||||
import app from "../public/locales/en/app.json";
|
import type app from "../public/locales/en/app.json";
|
||||||
|
|
||||||
interface I18nNamespaces {
|
interface I18nNamespaces {
|
||||||
app: typeof app;
|
app: typeof app;
|
||||||
|
|
5
apps/web/declarations/next-auth.d.ts
vendored
5
apps/web/declarations/next-auth.d.ts
vendored
|
@ -1,8 +1,7 @@
|
||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
||||||
import type { TimeFormat } from "@rallly/database";
|
import type { TimeFormat } from "@rallly/database";
|
||||||
import { extend } from "lodash";
|
import { extend } from "lodash";
|
||||||
import NextAuth, { DefaultSession, DefaultUser } from "next-auth";
|
import NextAuth, { type DefaultSession, type DefaultUser } from "next-auth";
|
||||||
import { DefaultJWT, JWT } from "next-auth/jwt";
|
import { type DefaultJWT, JWT } from "next-auth/jwt";
|
||||||
|
|
||||||
declare module "next-auth" {
|
declare module "next-auth" {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
"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",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "eslint .",
|
|
||||||
"type-check": "tsc --pretty --noEmit",
|
"type-check": "tsc --pretty --noEmit",
|
||||||
"i18n:scan": "i18next-scanner --config i18next-scanner.config.js",
|
"i18n:scan": "i18next-scanner --config i18next-scanner.config.js",
|
||||||
"prettier": "prettier --write ./src",
|
"prettier": "prettier --write ./src",
|
||||||
|
@ -88,7 +87,6 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@next/env": "^14.2.15",
|
"@next/env": "^14.2.15",
|
||||||
"@playwright/test": "^1.39.0",
|
"@playwright/test": "^1.39.0",
|
||||||
"@rallly/eslint-config": "workspace:*",
|
|
||||||
"@rallly/tsconfig": "workspace:*",
|
"@rallly/tsconfig": "workspace:*",
|
||||||
"@types/accept-language-parser": "^1.5.3",
|
"@types/accept-language-parser": "^1.5.3",
|
||||||
"@types/color-hash": "^1.0.2",
|
"@types/color-hash": "^1.0.2",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { loadEnvConfig } from "@next/env";
|
import { loadEnvConfig } from "@next/env";
|
||||||
import { devices, PlaywrightTestConfig } from "@playwright/test";
|
import { devices, type PlaywrightTestConfig } from "@playwright/test";
|
||||||
|
|
||||||
const ci = process.env.CI === "true";
|
const ci = process.env.CI === "true";
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { cn } from "@rallly/ui";
|
import { cn } from "@rallly/ui";
|
||||||
import { BarChart2Icon } from "lucide-react";
|
import { BarChart2Icon } from "lucide-react";
|
||||||
import React from "react";
|
import type React from "react";
|
||||||
|
|
||||||
export function AppCard({
|
export function AppCard({
|
||||||
children,
|
children,
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { Card, CardContent } from "@rallly/ui/card";
|
||||||
import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
|
import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
import { ScheduledEvent } from "@/app/[locale]/(admin)/events/types";
|
import type { ScheduledEvent } from "@/app/[locale]/(admin)/events/types";
|
||||||
import { Trans } from "@/components/trans";
|
import { Trans } from "@/components/trans";
|
||||||
import { generateGradient } from "@/utils/color-hash";
|
import { generateGradient } from "@/utils/color-hash";
|
||||||
import { useDayjs } from "@/utils/dayjs";
|
import { useDayjs } from "@/utils/dayjs";
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { UserScheduledEvents } from "@/app/[locale]/(admin)/events/user-scheduled-events";
|
import { UserScheduledEvents } from "@/app/[locale]/(admin)/events/user-scheduled-events";
|
||||||
import { Params } from "@/app/[locale]/types";
|
import type { Params } from "@/app/[locale]/types";
|
||||||
import {
|
import {
|
||||||
PageContainer,
|
PageContainer,
|
||||||
PageContent,
|
PageContent,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { cn } from "@rallly/ui";
|
import { cn } from "@rallly/ui";
|
||||||
import React from "react";
|
import type React from "react";
|
||||||
|
|
||||||
import { MobileNavigation } from "@/app/[locale]/(admin)/mobile-navigation";
|
import { MobileNavigation } from "@/app/[locale]/(admin)/mobile-navigation";
|
||||||
import { ProBadge } from "@/app/[locale]/(admin)/pro-badge";
|
import { ProBadge } from "@/app/[locale]/(admin)/pro-badge";
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { cn } from "@rallly/ui";
|
||||||
import { Link } from "lucide-react";
|
import { Link } from "lucide-react";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
|
|
||||||
import { IconComponent } from "@/types";
|
import type { IconComponent } from "@/types";
|
||||||
|
|
||||||
export function MenuItem({
|
export function MenuItem({
|
||||||
href,
|
href,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Trans } from "react-i18next/TransWithoutContext";
|
import { Trans } from "react-i18next/TransWithoutContext";
|
||||||
|
|
||||||
import { Sidebar } from "@/app/[locale]/(admin)/sidebar";
|
import { Sidebar } from "@/app/[locale]/(admin)/sidebar";
|
||||||
import { Params } from "@/app/[locale]/types";
|
import type { Params } from "@/app/[locale]/types";
|
||||||
import {
|
import {
|
||||||
PageContainer,
|
PageContainer,
|
||||||
PageContent,
|
PageContent,
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { HomeIcon } from "lucide-react";
|
||||||
import { Trans } from "react-i18next/TransWithoutContext";
|
import { Trans } from "react-i18next/TransWithoutContext";
|
||||||
|
|
||||||
import Dashboard from "@/app/[locale]/(admin)/dashboard";
|
import Dashboard from "@/app/[locale]/(admin)/dashboard";
|
||||||
import { Params } from "@/app/[locale]/types";
|
import type { Params } from "@/app/[locale]/types";
|
||||||
import {
|
import {
|
||||||
PageContainer,
|
PageContainer,
|
||||||
PageContent,
|
PageContent,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { BarChart2Icon } from "lucide-react";
|
import { BarChart2Icon } from "lucide-react";
|
||||||
|
|
||||||
import { UserPolls } from "@/app/[locale]/(admin)/polls/user-polls";
|
import { UserPolls } from "@/app/[locale]/(admin)/polls/user-polls";
|
||||||
import { Params } from "@/app/[locale]/types";
|
import type { Params } from "@/app/[locale]/types";
|
||||||
import {
|
import {
|
||||||
PageContainer,
|
PageContainer,
|
||||||
PageContent,
|
PageContent,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
"use client";
|
"use client";
|
||||||
import { PollStatus } from "@rallly/database";
|
import type { PollStatus } from "@rallly/database";
|
||||||
import { cn } from "@rallly/ui";
|
import { cn } from "@rallly/ui";
|
||||||
import { Badge } from "@rallly/ui/badge";
|
import { Badge } from "@rallly/ui/badge";
|
||||||
import { Button } from "@rallly/ui/button";
|
import { Button } from "@rallly/ui/button";
|
||||||
|
@ -50,8 +50,8 @@ function FilteredPolls({ status }: { status: PollStatus }) {
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<ol className="space-y-4">
|
<ol className="space-y-4">
|
||||||
{data.pages.map((page, i) => (
|
{data.pages.map((page) => (
|
||||||
<li key={i}>
|
<li key={page.nextCursor}>
|
||||||
<PollsListView data={page.polls} />
|
<PollsListView data={page.polls} />
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
|
@ -102,7 +102,7 @@ function useQueryParam(name: string) {
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
return [
|
return [
|
||||||
searchParams?.get(name),
|
searchParams?.get(name),
|
||||||
function (value: string) {
|
(value: string) => {
|
||||||
const newParams = new URLSearchParams(searchParams?.toString());
|
const newParams = new URLSearchParams(searchParams?.toString());
|
||||||
newParams.set(name, value);
|
newParams.set(name, value);
|
||||||
window.history.replaceState(null, "", `?${newParams.toString()}`);
|
window.history.replaceState(null, "", `?${newParams.toString()}`);
|
||||||
|
|
|
@ -16,11 +16,11 @@ import { Trans } from "@/components/trans";
|
||||||
import { useSubscription } from "@/contexts/plan";
|
import { useSubscription } from "@/contexts/plan";
|
||||||
import { trpc } from "@/utils/trpc/client";
|
import { trpc } from "@/utils/trpc/client";
|
||||||
|
|
||||||
import { BillingPlans, PricingData } from "./billing-plans";
|
import { BillingPlans, type PricingData } from "./billing-plans";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
||||||
Paddle: any;
|
Paddle: any;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { pricingData } from "@rallly/billing/pricing";
|
||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
|
|
||||||
import { BillingPage } from "@/app/[locale]/(admin)/settings/billing/billing-page";
|
import { BillingPage } from "@/app/[locale]/(admin)/settings/billing/billing-page";
|
||||||
import { Params } from "@/app/[locale]/types";
|
import type { Params } from "@/app/[locale]/types";
|
||||||
import { getTranslation } from "@/app/i18n";
|
import { getTranslation } from "@/app/i18n";
|
||||||
import { env } from "@/env";
|
import { env } from "@/env";
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React from "react";
|
import type React from "react";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
PageContainer,
|
PageContainer,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Params } from "@/app/[locale]/types";
|
import type { Params } from "@/app/[locale]/types";
|
||||||
import { getTranslation } from "@/app/i18n";
|
import { getTranslation } from "@/app/i18n";
|
||||||
|
|
||||||
import { PreferencesPage } from "./preferences-page";
|
import { PreferencesPage } from "./preferences-page";
|
||||||
|
|
|
@ -7,7 +7,7 @@ import {
|
||||||
DialogDescription,
|
DialogDescription,
|
||||||
DialogFooter,
|
DialogFooter,
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogProps,
|
type DialogProps,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from "@rallly/ui/dialog";
|
} from "@rallly/ui/dialog";
|
||||||
import { Form, FormField, FormItem, FormMessage } from "@rallly/ui/form";
|
import { Form, FormField, FormItem, FormMessage } from "@rallly/ui/form";
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Params } from "@/app/[locale]/types";
|
import type { Params } from "@/app/[locale]/types";
|
||||||
import { getTranslation } from "@/app/i18n";
|
import { getTranslation } from "@/app/i18n";
|
||||||
|
|
||||||
import { ProfilePage } from "./profile-page";
|
import { ProfilePage } from "./profile-page";
|
||||||
|
|
|
@ -25,7 +25,7 @@ import { ProBadge } from "@/components/pro-badge";
|
||||||
import { Trans } from "@/components/trans";
|
import { Trans } from "@/components/trans";
|
||||||
import { IfGuest, useUser } from "@/components/user-provider";
|
import { IfGuest, useUser } from "@/components/user-provider";
|
||||||
import { IfFreeUser } from "@/contexts/plan";
|
import { IfFreeUser } from "@/contexts/plan";
|
||||||
import { IconComponent } from "@/types";
|
import type { IconComponent } from "@/types";
|
||||||
import { usePostHog } from "@/utils/posthog";
|
import { usePostHog } from "@/utils/posthog";
|
||||||
|
|
||||||
function NavItem({
|
function NavItem({
|
||||||
|
@ -64,9 +64,9 @@ export function Sidebar() {
|
||||||
const posthog = usePostHog();
|
const posthog = usePostHog();
|
||||||
return (
|
return (
|
||||||
<nav className="flex flex-1 flex-col ">
|
<nav className="flex flex-1 flex-col ">
|
||||||
<ul role="list" className="flex flex-1 flex-col gap-y-7">
|
<ul className="flex flex-1 flex-col gap-y-7">
|
||||||
<li>
|
<li>
|
||||||
<ul role="list" className="-mx-2 space-y-1">
|
<ul className="-mx-2 space-y-1">
|
||||||
<li>
|
<li>
|
||||||
<NavItem current={pathname === "/"} href="/" icon={HomeIcon}>
|
<NavItem current={pathname === "/"} href="/" icon={HomeIcon}>
|
||||||
<Trans i18nKey="home" defaults="Home" />
|
<Trans i18nKey="home" defaults="Home" />
|
||||||
|
@ -103,7 +103,7 @@ export function Sidebar() {
|
||||||
</Button>
|
</Button>
|
||||||
</li>
|
</li>
|
||||||
<li className="mt-auto">
|
<li className="mt-auto">
|
||||||
<ul role="list" className="-mx-2 space-y-1">
|
<ul className="-mx-2 space-y-1">
|
||||||
<IfFreeUser>
|
<IfFreeUser>
|
||||||
<li>
|
<li>
|
||||||
<PayWallDialog>
|
<PayWallDialog>
|
||||||
|
@ -113,7 +113,10 @@ export function Sidebar() {
|
||||||
}
|
}
|
||||||
asChild
|
asChild
|
||||||
>
|
>
|
||||||
<button className="mb-4 flex w-full flex-col rounded-md border bg-gray-50 px-4 py-3 focus:border-gray-300 focus:bg-gray-200">
|
<button
|
||||||
|
type="button"
|
||||||
|
className="mb-4 flex w-full flex-col rounded-md border bg-gray-50 px-4 py-3 focus:border-gray-300 focus:bg-gray-200"
|
||||||
|
>
|
||||||
<span className="mb-2 flex items-center gap-x-2">
|
<span className="mb-2 flex items-center gap-x-2">
|
||||||
<SparklesIcon className="size-5 text-gray-400" />
|
<SparklesIcon className="size-5 text-gray-400" />
|
||||||
<span className="text-sm font-bold">
|
<span className="text-sm font-bold">
|
||||||
|
@ -162,7 +165,7 @@ export function Sidebar() {
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<hr className="my-2" />
|
<hr className="my-2" />
|
||||||
<ul role="list" className="-mx-2 space-y-1">
|
<ul className="-mx-2 space-y-1">
|
||||||
<li>
|
<li>
|
||||||
<Button
|
<Button
|
||||||
asChild
|
asChild
|
||||||
|
|
|
@ -31,8 +31,8 @@ export function LoginForm() {
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: providers } = useQuery(["providers"], getProviders, {
|
const { data: providers } = useQuery(["providers"], getProviders, {
|
||||||
cacheTime: Infinity,
|
cacheTime: Number.POSITIVE_INFINITY,
|
||||||
staleTime: Infinity,
|
staleTime: Number.POSITIVE_INFINITY,
|
||||||
});
|
});
|
||||||
|
|
||||||
const session = useSession();
|
const session = useSession();
|
||||||
|
@ -223,8 +223,8 @@ export function LoginForm() {
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid gap-2.5">
|
<div className="grid gap-2.5">
|
||||||
{alternativeLoginMethods.map((method, i) => (
|
{alternativeLoginMethods.map((method) => (
|
||||||
<Button size="lg" key={i} onClick={method.login}>
|
<Button size="lg" key={method.name} onClick={method.login}>
|
||||||
{method.icon}
|
{method.icon}
|
||||||
{method.name}
|
{method.name}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
@ -2,7 +2,7 @@ import Link from "next/link";
|
||||||
import { Trans } from "react-i18next/TransWithoutContext";
|
import { Trans } from "react-i18next/TransWithoutContext";
|
||||||
|
|
||||||
import { LoginForm } from "@/app/[locale]/(auth)/login/login-form";
|
import { LoginForm } from "@/app/[locale]/(auth)/login/login-form";
|
||||||
import { Params } from "@/app/[locale]/types";
|
import type { Params } from "@/app/[locale]/types";
|
||||||
import { getTranslation } from "@/app/i18n";
|
import { getTranslation } from "@/app/i18n";
|
||||||
import { AuthCard } from "@/components/auth/auth-layout";
|
import { AuthCard } from "@/components/auth/auth-layout";
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { RegisterForm } from "@/app/[locale]/(auth)/register/register-page";
|
import { RegisterForm } from "@/app/[locale]/(auth)/register/register-page";
|
||||||
import { Params } from "@/app/[locale]/types";
|
import type { Params } from "@/app/[locale]/types";
|
||||||
import { getTranslation } from "@/app/i18n";
|
import { getTranslation } from "@/app/i18n";
|
||||||
|
|
||||||
export default async function Page() {
|
export default async function Page() {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { notFound } from "next/navigation";
|
||||||
import { Redirect } from "@/app/components/redirect";
|
import { Redirect } from "@/app/components/redirect";
|
||||||
import { absoluteUrl } from "@/utils/absolute-url";
|
import { absoluteUrl } from "@/utils/absolute-url";
|
||||||
|
|
||||||
import { PParams } from "./types";
|
import type { PParams } from "./types";
|
||||||
|
|
||||||
export default async function Page({ params }: { params: PParams }) {
|
export default async function Page({ params }: { params: PParams }) {
|
||||||
const { adminUrlId } = params;
|
const { adminUrlId } = params;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Params } from "@/app/[locale]/types";
|
import type { Params } from "@/app/[locale]/types";
|
||||||
|
|
||||||
export interface PParams extends Params {
|
export interface PParams extends Params {
|
||||||
adminUrlId: string;
|
adminUrlId: string;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"use client";
|
"use client";
|
||||||
import { notFound, useParams, useSearchParams } from "next/navigation";
|
import { notFound, useParams, useSearchParams } from "next/navigation";
|
||||||
import React from "react";
|
import type React from "react";
|
||||||
|
|
||||||
import { LegacyPollContextProvider } from "@/components/poll/poll-context-provider";
|
import { LegacyPollContextProvider } from "@/components/poll/poll-context-provider";
|
||||||
import { VisibilityProvider } from "@/components/visibility";
|
import { VisibilityProvider } from "@/components/visibility";
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { prisma } from "@rallly/database";
|
import { prisma } from "@rallly/database";
|
||||||
import { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
import { InvitePage } from "@/app/[locale]/invite/[urlId]/invite-page";
|
import { InvitePage } from "@/app/[locale]/invite/[urlId]/invite-page";
|
||||||
import { getTranslation } from "@/app/i18n";
|
import { getTranslation } from "@/app/i18n";
|
||||||
|
|
|
@ -3,9 +3,9 @@ import "../../style.css";
|
||||||
|
|
||||||
import languages from "@rallly/languages";
|
import languages from "@rallly/languages";
|
||||||
import { Toaster } from "@rallly/ui/toaster";
|
import { Toaster } from "@rallly/ui/toaster";
|
||||||
import { Viewport } from "next";
|
import type { Viewport } from "next";
|
||||||
import { Inter } from "next/font/google";
|
import { Inter } from "next/font/google";
|
||||||
import React from "react";
|
import type React from "react";
|
||||||
|
|
||||||
import { TimeZoneChangeDetector } from "@/app/[locale]/timezone-change-detector";
|
import { TimeZoneChangeDetector } from "@/app/[locale]/timezone-change-detector";
|
||||||
import { Providers } from "@/app/providers";
|
import { Providers } from "@/app/providers";
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { Trans } from "react-i18next/TransWithoutContext";
|
||||||
|
|
||||||
import { GroupPollIcon } from "@/app/[locale]/(admin)/app-card";
|
import { GroupPollIcon } from "@/app/[locale]/(admin)/app-card";
|
||||||
import { BackButton } from "@/app/[locale]/(admin)/menu/menu-button";
|
import { BackButton } from "@/app/[locale]/(admin)/menu/menu-button";
|
||||||
import { Params } from "@/app/[locale]/types";
|
import type { Params } from "@/app/[locale]/types";
|
||||||
import { getTranslation } from "@/app/i18n";
|
import { getTranslation } from "@/app/i18n";
|
||||||
import { CreatePoll } from "@/components/create-poll";
|
import { CreatePoll } from "@/components/create-poll";
|
||||||
import { UserDropdown } from "@/components/user-dropdown";
|
import { UserDropdown } from "@/components/user-dropdown";
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { notFound } from "next/navigation";
|
||||||
import { Redirect } from "@/app/components/redirect";
|
import { Redirect } from "@/app/components/redirect";
|
||||||
import { absoluteUrl } from "@/utils/absolute-url";
|
import { absoluteUrl } from "@/utils/absolute-url";
|
||||||
|
|
||||||
import { PParams } from "./types";
|
import type { PParams } from "./types";
|
||||||
|
|
||||||
export default async function Page({ params }: { params: PParams }) {
|
export default async function Page({ params }: { params: PParams }) {
|
||||||
const { participantUrlId } = params;
|
const { participantUrlId } = params;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Params } from "@/app/[locale]/types";
|
import type { Params } from "@/app/[locale]/types";
|
||||||
|
|
||||||
export interface PParams extends Params {
|
export interface PParams extends Params {
|
||||||
participantUrlId: string;
|
participantUrlId: string;
|
||||||
|
|
|
@ -7,7 +7,7 @@ import {
|
||||||
DialogDescription,
|
DialogDescription,
|
||||||
DialogFooter,
|
DialogFooter,
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogProps,
|
type DialogProps,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from "@rallly/ui/dialog";
|
} from "@rallly/ui/dialog";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
|
|
@ -14,13 +14,13 @@ import { useRouter } from "next/navigation";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
PollDetailsData,
|
type PollDetailsData,
|
||||||
PollDetailsForm,
|
PollDetailsForm,
|
||||||
} from "@/components/forms/poll-details-form";
|
} from "@/components/forms/poll-details-form";
|
||||||
import { useUpdatePollMutation } from "@/components/poll/mutations";
|
import { useUpdatePollMutation } from "@/components/poll/mutations";
|
||||||
import { usePoll } from "@/components/poll-context";
|
import { usePoll } from "@/components/poll-context";
|
||||||
import { Trans } from "@/components/trans";
|
import { Trans } from "@/components/trans";
|
||||||
import { NextPageWithLayout } from "@/types";
|
import type { NextPageWithLayout } from "@/types";
|
||||||
|
|
||||||
const Page: NextPageWithLayout = () => {
|
const Page: NextPageWithLayout = () => {
|
||||||
const { poll } = usePoll();
|
const { poll } = usePoll();
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { useRouter } from "next/navigation";
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
|
|
||||||
import { PollOptionsData } from "@/components/forms";
|
import type { PollOptionsData } from "@/components/forms";
|
||||||
import PollOptionsForm from "@/components/forms/poll-options-form";
|
import PollOptionsForm from "@/components/forms/poll-options-form";
|
||||||
import { useModalContext } from "@/components/modal/modal-provider";
|
import { useModalContext } from "@/components/modal/modal-provider";
|
||||||
import { useUpdatePollMutation } from "@/components/poll/mutations";
|
import { useUpdatePollMutation } from "@/components/poll/mutations";
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { useForm } from "react-hook-form";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
PollSettingsForm,
|
PollSettingsForm,
|
||||||
PollSettingsFormData,
|
type PollSettingsFormData,
|
||||||
} from "@/components/forms/poll-settings";
|
} from "@/components/forms/poll-settings";
|
||||||
import { useUpdatePollMutation } from "@/components/poll/mutations";
|
import { useUpdatePollMutation } from "@/components/poll/mutations";
|
||||||
import { Trans } from "@/components/trans";
|
import { Trans } from "@/components/trans";
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { NextRequest, NextResponse } from "next/server";
|
import { type NextRequest, NextResponse } from "next/server";
|
||||||
|
|
||||||
import { resetUser } from "@/app/guest";
|
import { resetUser } from "@/app/guest";
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { GetObjectCommand } from "@aws-sdk/client-s3";
|
import { GetObjectCommand } from "@aws-sdk/client-s3";
|
||||||
import { NextRequest, NextResponse } from "next/server";
|
import { type NextRequest, NextResponse } from "next/server";
|
||||||
|
|
||||||
import { env } from "@/env";
|
import { env } from "@/env";
|
||||||
import { getS3Client } from "@/utils/s3";
|
import { getS3Client } from "@/utils/s3";
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
"use client";
|
"use client";
|
||||||
import { Button, ButtonProps } from "@rallly/ui/button";
|
import { Button, type ButtonProps } from "@rallly/ui/button";
|
||||||
|
|
||||||
import { usePostHog } from "@/utils/posthog";
|
import { usePostHog } from "@/utils/posthog";
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import { cn } from "@rallly/ui";
|
import { cn } from "@rallly/ui";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
import React from "react";
|
import type React from "react";
|
||||||
|
|
||||||
export function TabMenuItem({
|
export function TabMenuItem({
|
||||||
href,
|
href,
|
||||||
|
|
|
@ -4,13 +4,17 @@ import * as Sentry from "@sentry/nextjs";
|
||||||
import NextError from "next/error";
|
import NextError from "next/error";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
|
|
||||||
export default function GlobalError({ error }: { error: Error & { digest?: string } }) {
|
export default function GlobalError({
|
||||||
|
error,
|
||||||
|
}: {
|
||||||
|
error: Error & { digest?: string };
|
||||||
|
}) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
Sentry.captureException(error);
|
Sentry.captureException(error);
|
||||||
}, [error]);
|
}, [error]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html>
|
<html lang="en">
|
||||||
<body>
|
<body>
|
||||||
{/* `NextError` is the default Next.js error page component. Its type
|
{/* `NextError` is the default Next.js error page component. Its type
|
||||||
definition requires a `statusCode` prop. However, since the App Router
|
definition requires a `statusCode` prop. However, since the App Router
|
||||||
|
@ -20,4 +24,4 @@ export default function GlobalError({ error }: { error: Error & { digest?: strin
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import languages from "@rallly/languages";
|
import languages from "@rallly/languages";
|
||||||
import languageParser from "accept-language-parser";
|
import languageParser from "accept-language-parser";
|
||||||
import { NextRequest, NextResponse } from "next/server";
|
import type { NextRequest, NextResponse } from "next/server";
|
||||||
import { encode, JWT } from "next-auth/jwt";
|
import { encode, type JWT } from "next-auth/jwt";
|
||||||
|
|
||||||
import { absoluteUrl } from "@/utils/absolute-url";
|
import { absoluteUrl } from "@/utils/absolute-url";
|
||||||
import { randomid } from "@/utils/nanoid";
|
import { randomid } from "@/utils/nanoid";
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { createInstance, Namespace } from "i18next";
|
import { createInstance, type Namespace } from "i18next";
|
||||||
import resourcesToBackend from "i18next-resources-to-backend";
|
import resourcesToBackend from "i18next-resources-to-backend";
|
||||||
import { initReactI18next } from "react-i18next/initReactI18next";
|
import { initReactI18next } from "react-i18next/initReactI18next";
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
"use client";
|
"use client";
|
||||||
import i18next, { Namespace } from "i18next";
|
import i18next, { type Namespace } from "i18next";
|
||||||
import ICU from "i18next-icu";
|
import ICU from "i18next-icu";
|
||||||
import resourcesToBackend from "i18next-resources-to-backend";
|
import resourcesToBackend from "i18next-resources-to-backend";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
import React from "react";
|
import type React from "react";
|
||||||
import {
|
import {
|
||||||
I18nextProvider,
|
I18nextProvider,
|
||||||
initReactI18next,
|
initReactI18next,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import allLanguages from "@rallly/languages";
|
import allLanguages from "@rallly/languages";
|
||||||
import { InitOptions } from "i18next";
|
import type { InitOptions } from "i18next";
|
||||||
|
|
||||||
export const fallbackLng = "en";
|
export const fallbackLng = "en";
|
||||||
export const languages = Object.keys(allLanguages);
|
export const languages = Object.keys(allLanguages);
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { useState } from "react";
|
||||||
|
|
||||||
import { I18nProvider } from "@/app/i18n/client";
|
import { I18nProvider } from "@/app/i18n/client";
|
||||||
import { UserProvider } from "@/components/user-provider";
|
import { UserProvider } from "@/components/user-provider";
|
||||||
import { AppRouter } from "@/trpc/routers";
|
import type { AppRouter } from "@/trpc/routers";
|
||||||
import { ConnectedDayjsProvider } from "@/utils/dayjs";
|
import { ConnectedDayjsProvider } from "@/utils/dayjs";
|
||||||
import { trpcConfig } from "@/utils/trpc/config";
|
import { trpcConfig } from "@/utils/trpc/config";
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
} from "@rallly/ui/dropdown-menu";
|
} from "@rallly/ui/dropdown-menu";
|
||||||
import { Icon } from "@rallly/ui/icon";
|
import { Icon } from "@rallly/ui/icon";
|
||||||
import {
|
import {
|
||||||
CalendarEvent,
|
type CalendarEvent,
|
||||||
google,
|
google,
|
||||||
ics,
|
ics,
|
||||||
office365,
|
office365,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Button } from "@rallly/ui/button";
|
import { Button } from "@rallly/ui/button";
|
||||||
import { Input } from "@rallly/ui/input";
|
import { Input } from "@rallly/ui/input";
|
||||||
import { Trans, useTranslation } from "next-i18next";
|
import { Trans, useTranslation } from "next-i18next";
|
||||||
import React from "react";
|
import type React from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
|
|
||||||
import { requiredString } from "../../utils/form-validation";
|
import { requiredString } from "../../utils/form-validation";
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React from "react";
|
import type React from "react";
|
||||||
|
|
||||||
import { Logo } from "@/components/logo";
|
import { Logo } from "@/components/logo";
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ const CookieConsentPopover = () => {
|
||||||
Privacy Policy
|
Privacy Policy
|
||||||
</Link>
|
</Link>
|
||||||
<button
|
<button
|
||||||
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
Cookies.set("rallly_cookie_consent", "1", { expires: 365 });
|
Cookies.set("rallly_cookie_consent", "1", { expires: 365 });
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {
|
||||||
} from "@rallly/ui/card";
|
} from "@rallly/ui/card";
|
||||||
import { Form } from "@rallly/ui/form";
|
import { Form } from "@rallly/ui/form";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import React from "react";
|
import type React from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import useFormPersist from "react-hook-form-persist";
|
import useFormPersist from "react-hook-form-persist";
|
||||||
import { useUnmount } from "react-use";
|
import { useUnmount } from "react-use";
|
||||||
|
@ -21,7 +21,7 @@ import { setCookie } from "@/utils/cookies";
|
||||||
import { usePostHog } from "@/utils/posthog";
|
import { usePostHog } from "@/utils/posthog";
|
||||||
import { trpc } from "@/utils/trpc/client";
|
import { trpc } from "@/utils/trpc/client";
|
||||||
|
|
||||||
import { NewEventData, PollDetailsForm, PollOptionsForm } from "./forms";
|
import { type NewEventData, PollDetailsForm, PollOptionsForm } from "./forms";
|
||||||
|
|
||||||
const required = <T,>(v: T | undefined): T => {
|
const required = <T,>(v: T | undefined): T => {
|
||||||
if (!v) {
|
if (!v) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { cn } from "@rallly/ui";
|
import { cn } from "@rallly/ui";
|
||||||
import * as React from "react";
|
import type * as React from "react";
|
||||||
|
|
||||||
export interface DateCardProps {
|
export interface DateCardProps {
|
||||||
day: string;
|
day: string;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { cn } from "@rallly/ui";
|
import { cn } from "@rallly/ui";
|
||||||
import dayjs, { Dayjs } from "dayjs";
|
import dayjs, { type Dayjs } from "dayjs";
|
||||||
|
|
||||||
export const DateIconInner = (props: {
|
export const DateIconInner = (props: {
|
||||||
dow?: React.ReactNode;
|
dow?: React.ReactNode;
|
||||||
|
|
|
@ -65,9 +65,8 @@ function NewCommentForm({
|
||||||
if (user.isGuest) {
|
if (user.isGuest) {
|
||||||
const participant = participants.find((p) => p.userId === user.id);
|
const participant = participants.find((p) => p.userId === user.id);
|
||||||
return participant?.name ?? "";
|
return participant?.name ?? "";
|
||||||
} else {
|
|
||||||
return user.name;
|
|
||||||
}
|
}
|
||||||
|
return user.name;
|
||||||
}, [user, participants]);
|
}, [user, participants]);
|
||||||
|
|
||||||
const pollId = poll.id;
|
const pollId = poll.id;
|
||||||
|
@ -237,7 +236,10 @@ function DiscussionInner() {
|
||||||
{canDelete && (
|
{canDelete && (
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild={true}>
|
<DropdownMenuTrigger asChild={true}>
|
||||||
<button className="hover:text-foreground text-gray-500">
|
<button
|
||||||
|
type="button"
|
||||||
|
className="hover:text-foreground text-gray-500"
|
||||||
|
>
|
||||||
<MoreHorizontalIcon className="size-4" />
|
<MoreHorizontalIcon className="size-4" />
|
||||||
</button>
|
</button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
|
@ -281,6 +283,7 @@ function DiscussionInner() {
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<button
|
<button
|
||||||
|
type="button"
|
||||||
className="border-input text-muted-foreground flex w-full rounded border bg-transparent px-2 py-2 text-left text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-1"
|
className="border-input text-muted-foreground flex w-full rounded border bg-transparent px-2 py-2 text-left text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-1"
|
||||||
onClick={() => setIsWriting(true)}
|
onClick={() => setIsWriting(true)}
|
||||||
>
|
>
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { Button } from "@rallly/ui/button";
|
||||||
import { FrownIcon } from "lucide-react";
|
import { FrownIcon } from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
import * as React from "react";
|
import type * as React from "react";
|
||||||
|
|
||||||
export interface ComponentProps {
|
export interface ComponentProps {
|
||||||
icon?: React.ComponentType<{ className?: string }>;
|
icon?: React.ComponentType<{ className?: string }>;
|
||||||
|
|
|
@ -13,8 +13,8 @@ import {
|
||||||
MegaphoneIcon,
|
MegaphoneIcon,
|
||||||
SmileIcon,
|
SmileIcon,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import Link from "next/link";
|
|
||||||
import { Trans } from "next-i18next";
|
import { Trans } from "next-i18next";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
const FeedbackButton = () => {
|
const FeedbackButton = () => {
|
||||||
return (
|
return (
|
||||||
|
@ -28,17 +28,14 @@ const FeedbackButton = () => {
|
||||||
</DropdownMenuLabel>
|
</DropdownMenuLabel>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItem asChild>
|
<DropdownMenuItem asChild>
|
||||||
<Link
|
<Link href="https://feedback.rallly.co/?b=feedback" target={"_blank"}>
|
||||||
href={`https://feedback.rallly.co/?b=feedback`}
|
|
||||||
target={"_blank"}
|
|
||||||
>
|
|
||||||
<SmileIcon className="mr-2 size-4" />
|
<SmileIcon className="mr-2 size-4" />
|
||||||
<Trans i18nKey="sendFeedback" defaults="Send Feedback" />
|
<Trans i18nKey="sendFeedback" defaults="Send Feedback" />
|
||||||
</Link>
|
</Link>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem asChild>
|
<DropdownMenuItem asChild>
|
||||||
<Link
|
<Link
|
||||||
href={`https://feedback.rallly.co/?b=feature-request`}
|
href="https://feedback.rallly.co/?b=feature-request"
|
||||||
target={"_blank"}
|
target={"_blank"}
|
||||||
>
|
>
|
||||||
<LightbulbIcon className="mr-2 size-4" />
|
<LightbulbIcon className="mr-2 size-4" />
|
||||||
|
@ -47,7 +44,7 @@ const FeedbackButton = () => {
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem asChild>
|
<DropdownMenuItem asChild>
|
||||||
<Link
|
<Link
|
||||||
href={`https://feedback.rallly.co/?b=bug-reports`}
|
href="https://feedback.rallly.co/?b=bug-reports"
|
||||||
target={"_blank"}
|
target={"_blank"}
|
||||||
>
|
>
|
||||||
<BugIcon className="mr-2 size-4" />
|
<BugIcon className="mr-2 size-4" />
|
||||||
|
@ -56,7 +53,7 @@ const FeedbackButton = () => {
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItem asChild>
|
<DropdownMenuItem asChild>
|
||||||
<Link href={`https://support.rallly.co`} target={"_blank"}>
|
<Link href="https://support.rallly.co" target={"_blank"}>
|
||||||
<LifeBuoyIcon className="mr-2 size-4" />
|
<LifeBuoyIcon className="mr-2 size-4" />
|
||||||
<Trans i18nKey={"getSupport"} defaults={"Get Support"} />
|
<Trans i18nKey={"getSupport"} defaults={"Get Support"} />
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { useFormContext } from "react-hook-form";
|
||||||
import { Trans } from "@/components/trans";
|
import { Trans } from "@/components/trans";
|
||||||
import { useFormValidation } from "@/utils/form-validation";
|
import { useFormValidation } from "@/utils/form-validation";
|
||||||
|
|
||||||
import { NewEventData } from "./types";
|
import type { NewEventData } from "./types";
|
||||||
|
|
||||||
export interface PollDetailsData {
|
export interface PollDetailsData {
|
||||||
title: string;
|
title: string;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Button } from "@rallly/ui/button";
|
import { Button } from "@rallly/ui/button";
|
||||||
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
|
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
import * as React from "react";
|
import type * as React from "react";
|
||||||
|
|
||||||
export interface DateNavigationToolbarProps {
|
export interface DateNavigationToolbarProps {
|
||||||
year: number;
|
year: number;
|
||||||
|
|
|
@ -23,7 +23,7 @@ import { useTranslation } from "next-i18next";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { useFormContext } from "react-hook-form";
|
import { useFormContext } from "react-hook-form";
|
||||||
|
|
||||||
import { NewEventData } from "@/components/forms";
|
import type { NewEventData } from "@/components/forms";
|
||||||
import { Trans } from "@/components/trans";
|
import { Trans } from "@/components/trans";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -34,8 +34,8 @@ import {
|
||||||
} from "../../../../utils/date-time-utils";
|
} from "../../../../utils/date-time-utils";
|
||||||
import DateCard from "../../../date-card";
|
import DateCard from "../../../date-card";
|
||||||
import { useHeadlessDatePicker } from "../../../headless-date-picker";
|
import { useHeadlessDatePicker } from "../../../headless-date-picker";
|
||||||
import { DateTimeOption } from "..";
|
import type { DateTimeOption } from "..";
|
||||||
import { DateTimePickerProps } from "../types";
|
import type { DateTimePickerProps } from "../types";
|
||||||
import { formatDateWithoutTime, formatDateWithoutTz } from "../utils";
|
import { formatDateWithoutTime, formatDateWithoutTz } from "../utils";
|
||||||
import TimePicker from "./time-picker";
|
import TimePicker from "./time-picker";
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,9 @@ import { useFormContext } from "react-hook-form";
|
||||||
import { TimeZoneCommand } from "@/components/time-zone-picker/time-zone-select";
|
import { TimeZoneCommand } from "@/components/time-zone-picker/time-zone-select";
|
||||||
|
|
||||||
import { getBrowserTimeZone } from "../../../utils/date-time-utils";
|
import { getBrowserTimeZone } from "../../../utils/date-time-utils";
|
||||||
import { NewEventData } from "../types";
|
import type { NewEventData } from "../types";
|
||||||
import MonthCalendar from "./month-calendar";
|
import MonthCalendar from "./month-calendar";
|
||||||
import { DateTimeOption } from "./types";
|
import type { DateTimeOption } from "./types";
|
||||||
import WeekCalendar from "./week-calendar";
|
import WeekCalendar from "./week-calendar";
|
||||||
|
|
||||||
export type PollOptionsData = {
|
export type PollOptionsData = {
|
||||||
|
|
|
@ -3,14 +3,14 @@ import "./rbc-overrides.css";
|
||||||
|
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { XIcon } from "lucide-react";
|
import { XIcon } from "lucide-react";
|
||||||
import React from "react";
|
import type React from "react";
|
||||||
import { Calendar, CalendarProps } from "react-big-calendar";
|
import { Calendar, type CalendarProps } from "react-big-calendar";
|
||||||
import { createBreakpoint } from "react-use";
|
import { createBreakpoint } from "react-use";
|
||||||
|
|
||||||
import { getDuration } from "../../../utils/date-time-utils";
|
import { getDuration } from "../../../utils/date-time-utils";
|
||||||
import DateNavigationToolbar from "./date-navigation-toolbar";
|
import DateNavigationToolbar from "./date-navigation-toolbar";
|
||||||
import dayjsLocalizer from "./dayjs-localizer";
|
import dayjsLocalizer from "./dayjs-localizer";
|
||||||
import { DateTimeOption, DateTimePickerProps } from "./types";
|
import type { DateTimeOption, DateTimePickerProps } from "./types";
|
||||||
import { formatDateWithoutTz } from "./utils";
|
import { formatDateWithoutTz } from "./utils";
|
||||||
|
|
||||||
const localizer = dayjsLocalizer(dayjs);
|
const localizer = dayjsLocalizer(dayjs);
|
||||||
|
@ -47,12 +47,11 @@ const WeekCalendar: React.FunctionComponent<DateTimePickerProps> = ({
|
||||||
events={options.map((option) => {
|
events={options.map((option) => {
|
||||||
if (option.type === "date") {
|
if (option.type === "date") {
|
||||||
return { start: new Date(option.date) };
|
return { start: new Date(option.date) };
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
start: new Date(option.start),
|
|
||||||
end: new Date(option.end),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
return {
|
||||||
|
start: new Date(option.start),
|
||||||
|
end: new Date(option.end),
|
||||||
|
};
|
||||||
})}
|
})}
|
||||||
culture="default"
|
culture="default"
|
||||||
onNavigate={onNavigate}
|
onNavigate={onNavigate}
|
||||||
|
@ -122,7 +121,7 @@ const WeekCalendar: React.FunctionComponent<DateTimePickerProps> = ({
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
week: {
|
week: {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
||||||
header: function Header({ date }: any) {
|
header: function Header({ date }: any) {
|
||||||
return (
|
return (
|
||||||
<span className="w-full rounded-md text-center text-sm tracking-tight">
|
<span className="w-full rounded-md text-center text-sm tracking-tight">
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { useDialog } from "@rallly/ui/dialog";
|
||||||
import { FormField } from "@rallly/ui/form";
|
import { FormField } from "@rallly/ui/form";
|
||||||
import { Switch } from "@rallly/ui/switch";
|
import { Switch } from "@rallly/ui/switch";
|
||||||
import { AtSignIcon, EyeIcon, MessageCircleIcon, VoteIcon } from "lucide-react";
|
import { AtSignIcon, EyeIcon, MessageCircleIcon, VoteIcon } from "lucide-react";
|
||||||
import React from "react";
|
import type React from "react";
|
||||||
import { useFormContext } from "react-hook-form";
|
import { useFormContext } from "react-hook-form";
|
||||||
import { Trans } from "react-i18next";
|
import { Trans } from "react-i18next";
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { PollSettingsFormData } from "@/components/forms/poll-settings";
|
import type { PollSettingsFormData } from "@/components/forms/poll-settings";
|
||||||
|
|
||||||
import { PollDetailsData } from "./poll-details-form";
|
import type { PollDetailsData } from "./poll-details-form";
|
||||||
import { PollOptionsData } from "./poll-options-form/poll-options-form";
|
import type { PollOptionsData } from "./poll-options-form/poll-options-form";
|
||||||
|
|
||||||
export type NewEventData = PollDetailsData &
|
export type NewEventData = PollDetailsData &
|
||||||
PollOptionsData &
|
PollOptionsData &
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useParams, usePathname } from "next/navigation";
|
import { useParams, usePathname } from "next/navigation";
|
||||||
import React from "react";
|
import type React from "react";
|
||||||
|
|
||||||
import { GroupPollIcon } from "@/app/[locale]/(admin)/app-card";
|
import { GroupPollIcon } from "@/app/[locale]/(admin)/app-card";
|
||||||
import Loader from "@/app/[locale]/poll/[urlId]/skeleton";
|
import Loader from "@/app/[locale]/poll/[urlId]/skeleton";
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import Link, { LinkProps } from "next/link";
|
import Link, { type LinkProps } from "next/link";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import * as React from "react";
|
||||||
import { useList } from "react-use";
|
import { useList } from "react-use";
|
||||||
|
|
||||||
import { useRequiredContext } from "../use-required-context";
|
import { useRequiredContext } from "../use-required-context";
|
||||||
import Modal, { ModalProps } from "./modal";
|
import Modal, { type ModalProps } from "./modal";
|
||||||
|
|
||||||
export interface ModalProviderProps {
|
export interface ModalProviderProps {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Button, ButtonProps } from "@rallly/ui/button";
|
import { Button, type ButtonProps } from "@rallly/ui/button";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogClose,
|
DialogClose,
|
||||||
|
@ -7,7 +7,7 @@ import {
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from "@rallly/ui/dialog";
|
} from "@rallly/ui/dialog";
|
||||||
import * as React from "react";
|
import type * as React from "react";
|
||||||
|
|
||||||
export interface ModalProps {
|
export interface ModalProps {
|
||||||
title?: React.ReactNode;
|
title?: React.ReactNode;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import Modal, { ModalProps } from "./modal";
|
import Modal, { type ModalProps } from "./modal";
|
||||||
|
|
||||||
type OpenModalFn = () => void;
|
type OpenModalFn = () => void;
|
||||||
type CloseModalFn = () => void;
|
type CloseModalFn = () => void;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { VoteType } from "@rallly/database";
|
import type { VoteType } from "@rallly/database";
|
||||||
import { cn } from "@rallly/ui";
|
import { cn } from "@rallly/ui";
|
||||||
import { Badge } from "@rallly/ui/badge";
|
import { Badge } from "@rallly/ui/badge";
|
||||||
import { Button } from "@rallly/ui/button";
|
import { Button } from "@rallly/ui/button";
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Container } from "@/components/container";
|
import { Container } from "@/components/container";
|
||||||
import { IconComponent } from "@/types";
|
import type { IconComponent } from "@/types";
|
||||||
|
|
||||||
export const PageDialog = (
|
export const PageDialog = (
|
||||||
props: React.PropsWithChildren<{ icon?: IconComponent }>,
|
props: React.PropsWithChildren<{ icon?: IconComponent }>,
|
||||||
|
|
|
@ -10,7 +10,7 @@ interface ParticipantAvatarBarProps {
|
||||||
|
|
||||||
export const ParticipantAvatarBar = ({
|
export const ParticipantAvatarBar = ({
|
||||||
participants,
|
participants,
|
||||||
max = Infinity,
|
max = Number.POSITIVE_INFINITY,
|
||||||
}: ParticipantAvatarBarProps) => {
|
}: ParticipantAvatarBarProps) => {
|
||||||
const visibleCount = participants.length > max ? max - 1 : max;
|
const visibleCount = participants.length > max ? max - 1 : max;
|
||||||
const hiddenCount = participants.length - visibleCount;
|
const hiddenCount = participants.length - visibleCount;
|
||||||
|
|
|
@ -30,7 +30,7 @@ import { Input } from "@rallly/ui/input";
|
||||||
import { PencilIcon, TagIcon, TrashIcon } from "lucide-react";
|
import { PencilIcon, TagIcon, TrashIcon } from "lucide-react";
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { SubmitHandler, useForm } from "react-hook-form";
|
import { type SubmitHandler, useForm } from "react-hook-form";
|
||||||
import { useMount } from "react-use";
|
import { useMount } from "react-use";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { Participant, VoteType } from "@rallly/database";
|
import type { Participant, VoteType } from "@rallly/database";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
|
||||||
import { useVisibility } from "@/components/visibility";
|
import { useVisibility } from "@/components/visibility";
|
||||||
import { usePermissions } from "@/contexts/permissions";
|
import { usePermissions } from "@/contexts/permissions";
|
||||||
import { trpc } from "@/utils/trpc/client";
|
import { trpc } from "@/utils/trpc/client";
|
||||||
import { Vote } from "@/utils/trpc/types";
|
import type { Vote } from "@/utils/trpc/types";
|
||||||
|
|
||||||
import { useRequiredContext } from "./use-required-context";
|
import { useRequiredContext } from "./use-required-context";
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ export const ParticipantsProvider: React.FunctionComponent<{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
staleTime: 1000 * 10,
|
staleTime: 1000 * 10,
|
||||||
cacheTime: Infinity,
|
cacheTime: Number.POSITIVE_INFINITY,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { Badge } from "@rallly/ui/badge";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogProps,
|
type DialogProps,
|
||||||
useDialog,
|
useDialog,
|
||||||
} from "@rallly/ui/dialog";
|
} from "@rallly/ui/dialog";
|
||||||
import { RadioGroup, RadioGroupItem } from "@rallly/ui/radio-group";
|
import { RadioGroup, RadioGroupItem } from "@rallly/ui/radio-group";
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Participant, VoteType } from "@rallly/database";
|
import type { Participant, VoteType } from "@rallly/database";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { keyBy } from "lodash";
|
import { keyBy } from "lodash";
|
||||||
import { TrashIcon } from "lucide-react";
|
import { TrashIcon } from "lucide-react";
|
||||||
|
@ -6,12 +6,12 @@ import { useTranslation } from "next-i18next";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
type ParsedDateOption,
|
||||||
|
type ParsedTimeSlotOption,
|
||||||
getDuration,
|
getDuration,
|
||||||
ParsedDateOption,
|
|
||||||
ParsedTimeSlotOption,
|
|
||||||
} from "@/utils/date-time-utils";
|
} from "@/utils/date-time-utils";
|
||||||
import { useDayjs } from "@/utils/dayjs";
|
import { useDayjs } from "@/utils/dayjs";
|
||||||
import { GetPollApiResponse, Vote } from "@/utils/trpc/types";
|
import type { GetPollApiResponse, Vote } from "@/utils/trpc/types";
|
||||||
|
|
||||||
import ErrorPage from "./error-page";
|
import ErrorPage from "./error-page";
|
||||||
import { useParticipants } from "./participants-provider";
|
import { useParticipants } from "./participants-provider";
|
||||||
|
@ -59,9 +59,9 @@ export const PollContextProvider: React.FunctionComponent<{
|
||||||
(optionId: string) => {
|
(optionId: string) => {
|
||||||
return (participants ?? []).reduce(
|
return (participants ?? []).reduce(
|
||||||
(acc, curr) => {
|
(acc, curr) => {
|
||||||
curr.votes.forEach((vote) => {
|
for (const vote of curr.votes) {
|
||||||
if (vote.optionId !== optionId) {
|
if (vote.optionId !== optionId) {
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
if (vote.type === "yes") {
|
if (vote.type === "yes") {
|
||||||
acc.yes += 1;
|
acc.yes += 1;
|
||||||
|
@ -72,7 +72,7 @@ export const PollContextProvider: React.FunctionComponent<{
|
||||||
} else {
|
} else {
|
||||||
acc.skip += 1;
|
acc.skip += 1;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
return acc;
|
return acc;
|
||||||
},
|
},
|
||||||
{ yes: 0, ifNeedBe: 0, no: 0, skip: 0 },
|
{ yes: 0, ifNeedBe: 0, no: 0, skip: 0 },
|
||||||
|
@ -103,14 +103,14 @@ export const PollContextProvider: React.FunctionComponent<{
|
||||||
);
|
);
|
||||||
|
|
||||||
const participantsByOptionId: Record<string, Participant[]> = {};
|
const participantsByOptionId: Record<string, Participant[]> = {};
|
||||||
poll.options.forEach((option) => {
|
for (const option of poll.options) {
|
||||||
participantsByOptionId[option.id] = (participants ?? []).filter(
|
participantsByOptionId[option.id] = (participants ?? []).filter(
|
||||||
(participant) =>
|
(participant) =>
|
||||||
participant.votes.some(
|
participant.votes.some(
|
||||||
({ type, optionId }) => optionId === option.id && type === "yes",
|
({ type, optionId }) => optionId === option.id && type === "yes",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
optionIds,
|
optionIds,
|
||||||
|
@ -208,38 +208,37 @@ function createOptionsContextValue(
|
||||||
} satisfies ParsedTimeSlotOption;
|
} satisfies ParsedTimeSlotOption;
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
pollType: "date",
|
|
||||||
options: pollOptions.map((option) => {
|
|
||||||
const localTime = sourceTimeZone
|
|
||||||
? dayjs(option.startTime).tz(targetTimeZone)
|
|
||||||
: dayjs(option.startTime).utc();
|
|
||||||
|
|
||||||
return {
|
|
||||||
optionId: option.id,
|
|
||||||
type: "date",
|
|
||||||
month: localTime.format("MMM"),
|
|
||||||
day: localTime.format("D"),
|
|
||||||
dow: localTime.format("ddd"),
|
|
||||||
year: localTime.format("YYYY"),
|
|
||||||
} satisfies ParsedDateOption;
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
return {
|
||||||
|
pollType: "date",
|
||||||
|
options: pollOptions.map((option) => {
|
||||||
|
const localTime = sourceTimeZone
|
||||||
|
? dayjs(option.startTime).tz(targetTimeZone)
|
||||||
|
: dayjs(option.startTime).utc();
|
||||||
|
|
||||||
|
return {
|
||||||
|
optionId: option.id,
|
||||||
|
type: "date",
|
||||||
|
month: localTime.format("MMM"),
|
||||||
|
day: localTime.format("D"),
|
||||||
|
dow: localTime.format("ddd"),
|
||||||
|
year: localTime.format("YYYY"),
|
||||||
|
} satisfies ParsedDateOption;
|
||||||
|
}),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const OptionsProvider = (props: React.PropsWithChildren) => {
|
export const OptionsProvider = (props: React.PropsWithChildren) => {
|
||||||
const { poll } = usePoll();
|
const { poll } = usePoll();
|
||||||
const { timeZone: targetTimeZone, timeFormat } = useDayjs();
|
const { timeZone: targetTimeZone, timeFormat } = useDayjs();
|
||||||
|
|
||||||
|
// biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
|
||||||
const options = React.useMemo(() => {
|
const options = React.useMemo(() => {
|
||||||
return createOptionsContextValue(
|
return createOptionsContextValue(
|
||||||
poll.options,
|
poll.options,
|
||||||
targetTimeZone,
|
targetTimeZone,
|
||||||
poll.timeZone,
|
poll.timeZone,
|
||||||
);
|
);
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [poll.options, poll.timeZone, targetTimeZone, timeFormat]);
|
}, [poll.options, poll.timeZone, targetTimeZone, timeFormat]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { PollStatus } from "@rallly/database";
|
import type { PollStatus } from "@rallly/database";
|
||||||
import { cn } from "@rallly/ui";
|
import { cn } from "@rallly/ui";
|
||||||
|
|
||||||
import { Trans } from "@/components/trans";
|
import { Trans } from "@/components/trans";
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { Button } from "@rallly/ui/button";
|
||||||
import { Flex } from "@rallly/ui/flex";
|
import { Flex } from "@rallly/ui/flex";
|
||||||
import { Icon } from "@rallly/ui/icon";
|
import { Icon } from "@rallly/ui/icon";
|
||||||
import { MoreHorizontalIcon } from "lucide-react";
|
import { MoreHorizontalIcon } from "lucide-react";
|
||||||
import * as React from "react";
|
import type * as React from "react";
|
||||||
|
|
||||||
import { OptimizedAvatarImage } from "@/components/optimized-avatar-image";
|
import { OptimizedAvatarImage } from "@/components/optimized-avatar-image";
|
||||||
import { ParticipantName } from "@/components/participant";
|
import { ParticipantName } from "@/components/participant";
|
||||||
|
@ -14,7 +14,7 @@ import { usePoll } from "@/components/poll-context";
|
||||||
import { Trans } from "@/components/trans";
|
import { Trans } from "@/components/trans";
|
||||||
import { useUser } from "@/components/user-provider";
|
import { useUser } from "@/components/user-provider";
|
||||||
import { usePermissions } from "@/contexts/permissions";
|
import { usePermissions } from "@/contexts/permissions";
|
||||||
import { Vote } from "@/utils/trpc/types";
|
import type { Vote } from "@/utils/trpc/types";
|
||||||
|
|
||||||
import VoteIcon from "../vote-icon";
|
import VoteIcon from "../vote-icon";
|
||||||
import ParticipantRowForm from "./participant-row-form";
|
import ParticipantRowForm from "./participant-row-form";
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@rallly/ui/tooltip";
|
} from "@rallly/ui/tooltip";
|
||||||
import { ClockIcon } from "lucide-react";
|
import { ClockIcon } from "lucide-react";
|
||||||
import * as React from "react";
|
import type * as React from "react";
|
||||||
|
|
||||||
import { ConnectedScoreSummary } from "@/components/poll/score-summary";
|
import { ConnectedScoreSummary } from "@/components/poll/score-summary";
|
||||||
import { useOptions } from "@/components/poll-context";
|
import { useOptions } from "@/components/poll-context";
|
||||||
|
|
|
@ -7,7 +7,7 @@ import {
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from "@rallly/ui/dialog";
|
} from "@rallly/ui/dialog";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import * as React from "react";
|
import type * as React from "react";
|
||||||
|
|
||||||
import { Trans } from "@/components/trans";
|
import { Trans } from "@/components/trans";
|
||||||
import { usePostHog } from "@/utils/posthog";
|
import { usePostHog } from "@/utils/posthog";
|
||||||
|
|
|
@ -7,7 +7,7 @@ import {
|
||||||
DialogDescription,
|
DialogDescription,
|
||||||
DialogFooter,
|
DialogFooter,
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogProps,
|
type DialogProps,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from "@rallly/ui/dialog";
|
} from "@rallly/ui/dialog";
|
||||||
import {
|
import {
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue