Replace eslint with biome

This commit is contained in:
Luke Vella 2024-10-13 10:52:11 +01:00
parent 251e517810
commit cfb9ec8e8a
No known key found for this signature in database
GPG key ID: 469CAD687F0D784C
183 changed files with 422 additions and 409 deletions

View file

@ -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

View file

@ -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"]

View file

@ -1,4 +0,0 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
...require("@rallly/eslint-config")(__dirname),
};

View file

@ -1,4 +0,0 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
...require("@rallly/eslint-config")(__dirname),
};

View file

@ -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;

View file

@ -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",

View file

@ -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),

View file

@ -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"

View file

@ -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";

View file

@ -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";

View file

@ -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 }}
/> />
); );

View file

@ -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;

View file

@ -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,

View file

@ -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";

View file

@ -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,

View file

@ -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";

View file

@ -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);

View file

@ -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;

View file

@ -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",

View file

@ -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;

View file

@ -1,4 +0,0 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
...require("@rallly/eslint-config")(__dirname),
};

View file

@ -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;

View file

@ -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" {
/** /**

View file

@ -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",

View file

@ -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";

View file

@ -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,

View file

@ -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";

View file

@ -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,

View file

@ -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";

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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()}`);

View file

@ -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;
} }
} }

View file

@ -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";

View file

@ -1,4 +1,4 @@
import React from "react"; import type React from "react";
import { import {
PageContainer, PageContainer,

View file

@ -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";

View file

@ -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";

View file

@ -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";

View file

@ -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

View file

@ -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>

View file

@ -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";

View file

@ -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() {

View file

@ -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;

View file

@ -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;

View file

@ -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";

View file

@ -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";

View file

@ -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";

View file

@ -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";

View file

@ -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;

View file

@ -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;

View file

@ -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";

View file

@ -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();

View file

@ -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";

View file

@ -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";

View file

@ -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";

View file

@ -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";

View file

@ -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";

View file

@ -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,

View file

@ -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>
); );
} }

View file

@ -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";

View file

@ -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";

View file

@ -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,

View file

@ -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);

View file

@ -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";

View file

@ -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,

View file

@ -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";

View file

@ -1,4 +1,4 @@
import React from "react"; import type React from "react";
import { Logo } from "@/components/logo"; import { Logo } from "@/components/logo";

View file

@ -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);

View file

@ -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) {

View file

@ -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;

View file

@ -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;

View file

@ -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)}
> >

View file

@ -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 }>;

View file

@ -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>

View file

@ -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;

View file

@ -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;

View file

@ -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";

View file

@ -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 = {

View file

@ -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">

View file

@ -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";

View file

@ -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 &

View file

@ -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";

View file

@ -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";

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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";

View file

@ -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 }>,

View file

@ -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;

View file

@ -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";

View file

@ -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,
}, },
); );

View file

@ -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";

View file

@ -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 (

View file

@ -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";

View file

@ -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";

View file

@ -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";

View file

@ -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";

View file

@ -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