Compare commits

..

1 Commits

Author SHA1 Message Date
f4b12566bf fix(deps): update nextjs monorepo to v16
Some checks failed
Check / Lint and Check (push) Failing after 19s
Check / Lint and Check (pull_request) Failing after 19s
2025-11-01 02:01:36 +00:00
15 changed files with 662 additions and 696 deletions

6
.eslintrc.json Normal file
View File

@@ -0,0 +1,6 @@
{
"extends": [
"next/core-web-vitals",
"next/typescript"
]
}

View File

@@ -13,19 +13,19 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
- name: Install pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4
- name: Setup Node.js
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
with:
node-version: 24
node-version: 22
cache: "pnpm"
- name: Install dependencies
run: pnpm install
- name: Run check
run: pnpm run lint
run: pnpm run check

View File

@@ -41,7 +41,7 @@ export default function SignUp() {
// Double-check signup isn't blocked before submitting
const currentStatus = isSignupBlocked();
if (currentStatus.blocked) {
setResponse(currentStatus.message ?? "Sign-ups are currently closed.");
setResponse(currentStatus.message || "Sign-ups are currently closed.");
return;
}
setSubmitted(true);
@@ -50,7 +50,6 @@ export default function SignUp() {
function SignupForm() {
return (
<Form {...form}>
{/* eslint-disable-next-line @typescript-eslint/no-misused-promises */}
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<FormField
control={form.control}
@@ -91,10 +90,8 @@ export default function SignUp() {
<FormControl>
<Button
variant={"outline"}
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
className={cn("w-[240px] pl-3 text-left font-normal", field.value && "text-muted-foreground")}
className={cn("w-[240px] pl-3 text-left font-normal", !field.value && "text-muted-foreground")}
>
{/* eslint-disable-next-line @typescript-eslint/no-unnecessary-condition */}
{field.value ? format(field.value, "PPP") : <span>Pick a date</span>}
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
</Button>

View File

@@ -3,19 +3,26 @@
import * as React from "react";
import * as LabelPrimitive from "@radix-ui/react-label";
import { Slot } from "@radix-ui/react-slot";
import { Controller, ControllerProps, FieldPath, FieldValues, FormProvider, useFormContext } from "react-hook-form";
import {
Controller,
ControllerProps,
FieldPath,
FieldValues,
FormProvider,
useFormContext,
} from "react-hook-form";
import { cn } from "@/lib/utils";
import { Label } from "@/components/ui/label";
const Form = FormProvider;
interface FormFieldContextValue<
type FormFieldContextValue<
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
> {
> = {
name: TName;
}
};
const FormFieldContext = React.createContext<FormFieldContextValue>({} as FormFieldContextValue);
@@ -39,7 +46,7 @@ const useFormField = () => {
const fieldState = getFieldState(fieldContext.name, formState);
if (!fieldContext.name) {
if (!fieldContext) {
throw new Error("useFormField should be used within <FormField>");
}
@@ -55,9 +62,9 @@ const useFormField = () => {
};
};
interface FormItemContextValue {
type FormItemContextValue = {
id: string;
}
};
const FormItemContext = React.createContext<FormItemContextValue>({} as FormItemContextValue);
@@ -75,57 +82,88 @@ const FormItem = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivEl
FormItem.displayName = "FormItem";
const FormLabel = React.forwardRef<
React.ComponentRef<typeof LabelPrimitive.Root>,
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
>(({ className, ...props }, ref) => {
const { error, formItemId } = useFormField();
return <Label ref={ref} className={cn(error && "text-destructive", className)} htmlFor={formItemId} {...props} />;
return (
<Label
ref={ref}
className={cn(error && "text-destructive", className)}
htmlFor={formItemId}
{...props}
/>
);
});
FormLabel.displayName = "FormLabel";
const FormControl = React.forwardRef<React.ComponentRef<typeof Slot>, React.ComponentPropsWithoutRef<typeof Slot>>(
({ ...props }, ref) => {
const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
const FormControl = React.forwardRef<
React.ElementRef<typeof Slot>,
React.ComponentPropsWithoutRef<typeof Slot>
>(({ ...props }, ref) => {
const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
return (
<Slot
ref={ref}
id={formItemId}
aria-describedby={!error ? formDescriptionId : `${formDescriptionId} ${formMessageId}`}
aria-invalid={!!error}
{...props}
/>
);
}
);
return (
<Slot
ref={ref}
id={formItemId}
aria-describedby={!error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`}
aria-invalid={!!error}
{...props}
/>
);
});
FormControl.displayName = "FormControl";
const FormDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
({ className, ...props }, ref) => {
const { formDescriptionId } = useFormField();
const FormDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => {
const { formDescriptionId } = useFormField();
return <p ref={ref} id={formDescriptionId} className={cn("text-sm text-muted-foreground", className)} {...props} />;
}
);
return (
<p
ref={ref}
id={formDescriptionId}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
);
});
FormDescription.displayName = "FormDescription";
const FormMessage = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
({ className, children, ...props }, ref) => {
const { error, formMessageId } = useFormField();
const body = error ? String(error.message) : children;
const FormMessage = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, children, ...props }, ref) => {
const { error, formMessageId } = useFormField();
const body = error ? String(error?.message) : children;
if (!body) {
return null;
}
return (
<p ref={ref} id={formMessageId} className={cn("text-sm font-medium text-destructive", className)} {...props}>
{body}
</p>
);
if (!body) {
return null;
}
);
return (
<p
ref={ref}
id={formMessageId}
className={cn("text-sm font-medium text-destructive", className)}
{...props}
>
{body}
</p>
);
});
FormMessage.displayName = "FormMessage";
export { useFormField, Form, FormItem, FormLabel, FormControl, FormDescription, FormMessage, FormField };
export {
useFormField,
Form,
FormItem,
FormLabel,
FormControl,
FormDescription,
FormMessage,
FormField,
};

View File

@@ -11,7 +11,7 @@ const labelVariants = cva(
);
const Label = React.forwardRef<
React.ComponentRef<typeof LabelPrimitive.Root>,
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & VariantProps<typeof labelVariants>
>(({ className, ...props }, ref) => (
<LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />

View File

@@ -10,7 +10,7 @@ const Popover = PopoverPrimitive.Root;
const PopoverTrigger = PopoverPrimitive.Trigger;
const PopoverContent = React.forwardRef<
React.ComponentRef<typeof PopoverPrimitive.Content>,
React.ElementRef<typeof PopoverPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
<PopoverPrimitive.Portal>

View File

@@ -13,7 +13,7 @@ const SelectGroup = SelectPrimitive.Group;
const SelectValue = SelectPrimitive.Value;
const SelectTrigger = React.forwardRef<
React.ComponentRef<typeof SelectPrimitive.Trigger>,
React.ElementRef<typeof SelectPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Trigger
@@ -33,7 +33,7 @@ const SelectTrigger = React.forwardRef<
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
const SelectScrollUpButton = React.forwardRef<
React.ComponentRef<typeof SelectPrimitive.ScrollUpButton>,
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
>(({ className, ...props }, ref) => (
<SelectPrimitive.ScrollUpButton
@@ -47,7 +47,7 @@ const SelectScrollUpButton = React.forwardRef<
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
const SelectScrollDownButton = React.forwardRef<
React.ComponentRef<typeof SelectPrimitive.ScrollDownButton>,
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
>(({ className, ...props }, ref) => (
<SelectPrimitive.ScrollDownButton
@@ -61,7 +61,7 @@ const SelectScrollDownButton = React.forwardRef<
SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
const SelectContent = React.forwardRef<
React.ComponentRef<typeof SelectPrimitive.Content>,
React.ElementRef<typeof SelectPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
>(({ className, children, position = "popper", ...props }, ref) => (
<SelectPrimitive.Portal>
@@ -93,7 +93,7 @@ const SelectContent = React.forwardRef<
SelectContent.displayName = SelectPrimitive.Content.displayName;
const SelectLabel = React.forwardRef<
React.ComponentRef<typeof SelectPrimitive.Label>,
React.ElementRef<typeof SelectPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Label
@@ -105,7 +105,7 @@ const SelectLabel = React.forwardRef<
SelectLabel.displayName = SelectPrimitive.Label.displayName;
const SelectItem = React.forwardRef<
React.ComponentRef<typeof SelectPrimitive.Item>,
React.ElementRef<typeof SelectPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Item
@@ -128,7 +128,7 @@ const SelectItem = React.forwardRef<
SelectItem.displayName = SelectPrimitive.Item.displayName;
const SelectSeparator = React.forwardRef<
React.ComponentRef<typeof SelectPrimitive.Separator>,
React.ElementRef<typeof SelectPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Separator

View File

@@ -1,37 +0,0 @@
// @ts-check
import { defineConfig, globalIgnores } from "eslint/config";
import nextVitals from "eslint-config-next/core-web-vitals";
import nextTs from "eslint-config-next/typescript";
import tseslint from "typescript-eslint";
const eslintConfig = defineConfig([
// Next.js core-web-vitals and TypeScript configs
...nextVitals,
...nextTs,
// Add strict TypeScript rules on top
...tseslint.configs.strictTypeChecked,
...tseslint.configs.stylisticTypeChecked,
// Configure TypeScript parser options
{
files: ["**/*.{ts,tsx}"],
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
},
// Override default ignores of eslint-config-next
globalIgnores([
// Default ignores of eslint-config-next:
".next/**",
"out/**",
"build/**",
"next-env.d.ts",
// Additional ignores:
"*.mjs",
"tailwind.config.ts",
]),
]);
export default eslintConfig;

View File

@@ -1,12 +1,12 @@
import "server-only";
export interface listmonkData {
export type listmonkData = {
email: string;
name: string;
status: "enabled" | "blocklisted";
lists: number[];
attribs: Record<string, string>;
}
};
async function listmonk(data: listmonkData): Promise<string> {
const listmonkUrl = process.env.LISTMONK_URL ?? "http://localhost:9000/api/";

View File

@@ -5,7 +5,7 @@ function testScenario(description: string, date: Date, expected: boolean) {
const result = isSignupBlocked(date);
const status = result.blocked === expected ? "✅ PASS" : "❌ FAIL";
console.log(`${status} ${description}`);
console.log(` Expected blocked: ${String(expected)}, Got: ${String(result.blocked)}`);
console.log(` Expected blocked: ${expected}, Got: ${result.blocked}`);
if (result.message) {
console.log(` Message: ${result.message}`);
}

View File

@@ -1,7 +1,7 @@
import eventConfig from "@/event-dates.json";
export function isSignupBlocked(currentTime?: Date): { blocked: boolean; message?: string } {
const now = currentTime ?? new Date();
const now = currentTime || new Date();
const cutoffTime = eventConfig.cutoffTime || "15:00";
const blockDurationHours = eventConfig.blockDurationHours || 6;

View File

@@ -6,7 +6,7 @@
"dev": "next dev --turbopack",
"build": "next build",
"start": "next start",
"lint": "next typegen && eslint . && npx tsc --noEmit"
"check": "next lint && npx tsc --noEmit"
},
"dependencies": {
"@hookform/resolvers": "^5.1.1",
@@ -18,38 +18,31 @@
"clsx": "^2.1.1",
"cssnano": "^7.1.0",
"date-fns": "^4.1.0",
"lucide-react": "^0.554.0",
"next": "16.0.3",
"lucide-react": "^0.548.0",
"next": "^16.0.0",
"next-plausible": "^3.12.4",
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-preset-env": "^10.2.4",
"react": "19.2.0",
"react": "^19.1.0",
"react-day-picker": "^9.8.0",
"react-dom": "19.2.0",
"react-dom": "^19.1.0",
"react-hook-form": "^7.60.0",
"tailwind-merge": "^3.3.1",
"tailwindcss-animate": "^1.0.7",
"zod": "^4.0.5"
},
"devDependencies": {
"@tailwindcss/postcss": "4.1.17",
"@types/node": "24.10.1",
"@types/react": "19.2.6",
"@types/react-dom": "19.2.3",
"eslint": "9.39.1",
"eslint-config-next": "16.0.3",
"@tailwindcss/postcss": "4.1.16",
"@types/node": "22.18.13",
"@types/react": "19.2.2",
"@types/react-dom": "19.2.2",
"eslint": "9.38.0",
"eslint-config-next": "16.0.1",
"eslint-config-prettier": "10.1.8",
"postcss": "8.5.6",
"tailwindcss": "4.1.17",
"turbo": "2.6.1",
"typescript": "5.9.3",
"typescript-eslint": "^8.47.0"
"tailwindcss": "4.1.16",
"turbo": "2.5.8",
"typescript": "5.9.3"
},
"packageManager": "pnpm@10.23.0",
"pnpm": {
"overrides": {
"@types/react": "19.2.6",
"@types/react-dom": "19.2.3"
}
}
"packageManager": "pnpm@10.19.0"
}

1079
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,27 @@
const config = {
plugins: {
'@tailwindcss/postcss': {},
"postcss-flexbugs-fixes": {
"postcss-preset-env": {
autoprefixer: {
flexbox: "no-2009",
},
stage: 3,
features: {
"custom-properties": false,
},
},
"@fullhuman/postcss-purgecss": {
content: [
"./pages/**/*.{js,jsx,ts,tsx}",
"./components/**/*.{js,jsx,ts,tsx}",
],
defaultExtractor: (content) => content.match(/[\w-/:]+(?<!:)/g) || [],
safelist: ["html", "body"],
},
},
cssnano: {},
},
};

View File

@@ -10,7 +10,7 @@
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"jsx": "preserve",
"incremental": true,
"plugins": [
{
@@ -22,13 +22,6 @@
},
"target": "ES2023"
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
"event-dates.json",
".next/dev/types/**/*.ts"
],
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "event-dates.json"],
"exclude": ["node_modules"]
}