Compare commits

...

7 Commits

Author SHA1 Message Date
bd2ddd9bb6 fix misc issues, upgrade
All checks were successful
Check / Lint and Check (push) Successful in 1m38s
2025-07-15 17:33:11 +02:00
358dc77e5a disable sign-up on event day
Some checks failed
Check / Lint and Check (push) Failing after 30s
2025-07-15 16:28:02 +02:00
1108a66378 nextjs upgrade 2025-07-15 15:12:17 +02:00
bff627f4cf chore(deps): pin pnpm/action-setup action to a7487c7 (#11)
All checks were successful
Check / Lint and Check (push) Successful in 42s
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [pnpm/action-setup](https://github.com/pnpm/action-setup) | action | pinDigest |  -> `a7487c7` |

---

### Configuration

📅 **Schedule**: Branch creation - "every weekend" (UTC), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4zMS4xIiwidXBkYXRlZEluVmVyIjoiNDEuMzEuMSIsInRhcmdldEJyYW5jaCI6Im1hc3RlciIsImxhYmVscyI6W119-->

Reviewed-on: #11
Co-authored-by: Renovate Bot <renovatebot@schulze.network>
Co-committed-by: Renovate Bot <renovatebot@schulze.network>
2025-07-13 08:37:41 +02:00
9bbdf19897 pnpm ci
All checks were successful
Check / Lint and Check (push) Successful in 46s
2025-07-13 01:38:53 +02:00
723863b971 pnpm
Some checks failed
Check / Lint and Check (push) Failing after 6s
2025-07-13 01:19:03 +02:00
af49f49bbf fix(deps): update dependency zod to v4 (#10)
All checks were successful
Check / Lint and Check (push) Successful in 45s
This PR contains the following updates:

| Package | Change | Age | Confidence |
|---|---|---|---|
| [zod](https://zod.dev) ([source](https://github.com/colinhacks/zod)) | [`^3.24.2` -> `^4.0.0`](https://renovatebot.com/diffs/npm/zod/3.25.76/4.0.5) | [![age](https://developer.mend.io/api/mc/badges/age/npm/zod/4.0.5?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/zod/3.25.76/4.0.5?slim=true)](https://docs.renovatebot.com/merge-confidence/) |

---

### Release Notes

<details>
<summary>colinhacks/zod (zod)</summary>

### [`v4.0.5`](https://github.com/colinhacks/zod/releases/tag/v4.0.5)

[Compare Source](https://github.com/colinhacks/zod/compare/v4.0.4...v4.0.5)

#### Commits:

- [`f91a73e`](f91a73ec23) Support pipes in discriminated unions. Closes [#&#8203;4856](https://github.com/colinhacks/zod/issues/4856) ([#&#8203;4861](https://github.com/colinhacks/zod/issues/4861))
- [`45afab0`](45afab0f84) 4.0.5

### [`v4.0.4`](https://github.com/colinhacks/zod/releases/tag/v4.0.4)

[Compare Source](https://github.com/colinhacks/zod/compare/v4.0.3...v4.0.4)

#### Commits:

- [`9335f05`](9335f0543d) Adds `ZodFirstPartyTypeKind` stub to fix module resolution failure inside `zod-to-json-schema`

### [`v4.0.3`](https://github.com/colinhacks/zod/releases/tag/v4.0.3)

[Compare Source](44a936cb77...v4.0.3)

#### Commits:

- [`5905a8d`](5905a8d810) Improve check-versions script
- [`f3e749b`](f3e749b1b0) Remove global File interface
- [`44a936c`](44a936cb77) 4.0.2
- [`74006ed`](74006edd49) Fix JSR provenance
- [`ff4af5e`](ff4af5e889) 4.0.3
- [`ce573e8`](ce573e8799) Update test badge
- [`9a7161a`](9a7161a976) Fix versions

### [`v4.0.2`](https://github.com/colinhacks/zod/compare/v4.0.1...44a936cb77961e57a0988d8a3c63d9c71fce69ac)

[Compare Source](https://github.com/colinhacks/zod/compare/v4.0.1...44a936cb77961e57a0988d8a3c63d9c71fce69ac)

### [`v4.0.1`](https://github.com/colinhacks/zod/releases/tag/v4.0.1): v4.0.0

[Compare Source](79d4d80e3b...v4.0.1)

With this release, `zod@4.0.0` has been published to `npm`. There were no code changes between 3.25.76 and 4.0.0!

Zod 4 has been stable for the past 6 weeks, but it was published inside zod@3.25.x on npm. this transitionary window gave the ecosystem time to incrementally support for Zod 4 (without dropping support for Zod 3). As there is now near-universal support for Zod 4 in the ecosystem, ths time feels right to finally put a bow on things 🎀

To upgrade to Zod 4:

```
npm upgrade zod@^4.0.0
```

If you’ve already migrated to Zod 4 using the subpaths, there are no changes required. however you can optionally simplify your imports (recommended)

```ts
// after upgrading to zod@4.0.0:
import * as z from "zod"; // Zod 4 (regular)
import * as z from "zod/mini" // Zod 4 Mini

// these still work, but are no longer needed
import * as z from "zod/v4";
import * as z from "zod/v4-mini":

// if you still need Zod 3
import * as z from "zod/v3"; // Zod 3
```

**Library authors** — if you've already implemented Zod 4 support according to the best practices outlined in the [Library authors](/library-authors) guide, bump your peer dependency to include `zod@^4.0.0`:

```json
// package.json
{
  "peerDependencies": {
    "zod": "^3.25.0 || ^4.0.0"
  }
}
```

*There should be no other code changes necessary.* No code changes were made between the latest `3.25.x` release and `4.0.0`. This does not require a major version bump.

### [`v4.0.0`](https://github.com/colinhacks/zod/compare/v3.25.76...79d4d80e3b47f04752c5c281077b53f889551441)

[Compare Source](https://github.com/colinhacks/zod/compare/v3.25.76...79d4d80e3b47f04752c5c281077b53f889551441)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "every weekend" (UTC), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC40Ni4wIiwidXBkYXRlZEluVmVyIjoiNDEuMzEuMSIsInRhcmdldEJyYW5jaCI6Im1hc3RlciIsImxhYmVscyI6W119-->

Co-authored-by: Felix Schulze <admin@schulze.network>
Reviewed-on: #10
Co-authored-by: Renovate Bot <renovatebot@schulze.network>
Co-committed-by: Renovate Bot <renovatebot@schulze.network>
2025-07-13 00:09:18 +02:00
12 changed files with 6430 additions and 9530 deletions

View File

@@ -4,7 +4,7 @@ on:
pull_request:
push:
branches:
- '**' # matches every branch
- "**" # matches every branch
jobs:
lint_and_check:
@@ -15,14 +15,17 @@ jobs:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Install pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4
- name: Setup Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: 22
cache: 'npm'
cache: "pnpm"
- name: Install dependencies
run: npm ci
run: pnpm install
- name: Run check
run: npm run check
run: pnpm run check

44
EVENT_DATES_GUIDE.md Normal file
View File

@@ -0,0 +1,44 @@
# Event Dates Management Guide
## How to Block Sign-ups on Event Days
The sign-up form automatically closes at 3pm on specified event dates to prevent last-minute registrations.
### Managing Event Dates
1. Open the `event-dates.json` file in the project root
2. Add or remove dates in the `eventDates` array
3. Use the format `YYYY-MM-DD` (e.g., "2024-12-25" for December 25, 2024)
### Example Configuration
```json
{
"eventDates": ["2025-09-05", "1999-01-01"],
"cutoffTime": "15:00",
"message": "Sign-ups are closed for today's event. Please come back tomorrow."
}
```
### Important Notes
- The cutoff time is set to 3pm (15:00) by default
- Sign-ups will automatically reopen at midnight after an event day
- Users will see a friendly message when sign-ups are closed
- The time zone follows the server's local time
### Adding New Event Dates
Simply add a new date to the array:
```json
"eventDates": [
"2024-12-25",
"2024-12-31",
"2025-01-15",
"2025-02-14",
"2025-03-20" // <- New date added
]
```
Remember to save the file after making changes!

View File

@@ -5,15 +5,7 @@ import { useForm } from "react-hook-form";
import { z } from "zod";
import { Button } from "@/components/ui/button";
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { format } from "date-fns";
import { CalendarIcon } from "lucide-react";
import { Input } from "@/components/ui/input";
@@ -22,11 +14,12 @@ import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover
import { cn } from "@/lib/utils";
import { signupFormSubmit } from "@/lib/actions";
import { useState } from "react";
import { isSignupBlocked } from "@/lib/signup-time-check";
export const signupFormSchema = z.object({
name: z.string().min(2, { message: "Name is required" }).max(50, { message: "Name is too long" }),
email: z.string().email({ message: "Email is invalid" }),
dob: z.date({ required_error: "Birthday is required" }),
name: z.string().min(2, { error: "Name is required" }).max(50, { error: "Name is too long" }),
email: z.email({ error: "Email is invalid" }),
dob: z.date({ error: "Birthday is required" }),
});
export const youngestDate = new Date(new Date().setFullYear(new Date().getFullYear() - 20));
export const oldestDate = new Date(new Date().setFullYear(new Date().getFullYear() - 100));
@@ -34,6 +27,8 @@ export const oldestDate = new Date(new Date().setFullYear(new Date().getFullYear
export default function SignUp() {
const [submitted, setSubmitted] = useState(false);
const [response, setResponse] = useState<string | null>(null);
const signupStatus = isSignupBlocked();
const form = useForm<z.infer<typeof signupFormSchema>>({
resolver: zodResolver(signupFormSchema),
defaultValues: {
@@ -43,6 +38,12 @@ export default function SignUp() {
},
});
async function onSubmit(values: z.infer<typeof signupFormSchema>) {
// Double-check signup isn't blocked before submitting
const currentStatus = isSignupBlocked();
if (currentStatus.blocked) {
setResponse(currentStatus.message || "Sign-ups are currently closed.");
return;
}
setSubmitted(true);
setResponse(await signupFormSubmit(values));
}
@@ -59,9 +60,7 @@ export default function SignUp() {
<FormControl>
<Input placeholder="name@example.com" {...field} />
</FormControl>
<FormDescription>
We will contact you here with information about events.
</FormDescription>
<FormDescription>We will contact you here with information about events.</FormDescription>
<FormMessage />
</FormItem>
)}
@@ -91,10 +90,7 @@ export default function SignUp() {
<FormControl>
<Button
variant={"outline"}
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")}
>
{field.value ? format(field.value, "PPP") : <span>Pick a date</span>}
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
@@ -122,12 +118,22 @@ export default function SignUp() {
</FormItem>
)}
/>
<Button type="submit" disabled={submitted}>
<Button type="submit" disabled={submitted || signupStatus.blocked}>
Submit
</Button>
</form>
</Form>
);
}
// If signup is blocked, show the message
if (signupStatus.blocked && !response) {
return (
<div className="rounded-lg border bg-orange-50 p-6 text-center">
<p className="text-lg font-semibold text-orange-900 mb-2">Sign-ups Temporarily Closed</p>
<p className="text-orange-800">{signupStatus.message}</p>
</div>
);
}
return response ?? SignupForm();
}

View File

@@ -2,23 +2,17 @@ import * as React from "react";
import { cn } from "@/lib/utils";
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}
{...props}
/>
);
}
);
Input.displayName = "Input";
function Input({ className, type, ...props }: React.ComponentProps<"input">) {
return (
<input
type={type}
data-slot="input"
className={cn(
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
{...props}
/>
);
}
export { Input };

7
event-dates.json Normal file
View File

@@ -0,0 +1,7 @@
{
"eventDates": ["2025-09-05", "1999-01-01"],
"cutoffTime": "15:00",
"message": "Sign-ups are closed for today's event. Please come back tomorrow.",
"internalComment": "Add event dates in YYYY-MM-DD format. Signups will be disabled after 3pm (15:00) on these dates by default."
}

View File

@@ -29,7 +29,7 @@ async function listmonk(data: listmonkData): Promise<string> {
return "An error occurred or this email is already subscribed.";
}
return "Thanks for signing up! Please check your email for a confirmation.";
} catch (error) {
} catch {
return "An error occurred while trying to sign up. Please try again.";
}
}

23
lib/signup-time-check.ts Normal file
View File

@@ -0,0 +1,23 @@
import eventConfig from "@/event-dates.json";
export function isSignupBlocked(): { blocked: boolean; message?: string } {
const now = new Date();
const currentDate = now.toISOString().split("T")[0]; // YYYY-MM-DD format
const currentTime = now.toTimeString().slice(0, 5); // HH:MM format
// Check if today is an event date
const isEventDay = eventConfig.eventDates.includes(currentDate);
if (isEventDay) {
// Check if current time is after the cutoff time (default 15:00 / 3pm)
const cutoffTime = eventConfig.cutoffTime || "15:00";
if (currentTime >= cutoffTime) {
return {
blocked: true,
message: eventConfig.message,
};
}
}
return { blocked: false };
}

9466
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -9,27 +9,27 @@
"check": "next lint && npx tsc --noEmit"
},
"dependencies": {
"@hookform/resolvers": "^5.0.0",
"@radix-ui/react-label": "^2.1.2",
"@radix-ui/react-popover": "^1.1.6",
"@radix-ui/react-select": "^2.1.6",
"@radix-ui/react-slot": "^1.1.2",
"class-variance-authority": "^0.7.0",
"@hookform/resolvers": "^5.1.1",
"@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-popover": "^1.1.14",
"@radix-ui/react-select": "^2.2.5",
"@radix-ui/react-slot": "^1.2.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cssnano": "^7.0.1",
"date-fns": "^4.0.0",
"cssnano": "^7.1.0",
"date-fns": "^4.1.0",
"lucide-react": "^0.525.0",
"next": "^15.2.1",
"next-plausible": "^3.12.0",
"next": "^15.4.1",
"next-plausible": "^3.12.4",
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-preset-env": "^10.0.0",
"react": "^19.0.0",
"react-day-picker": "^9.5.1",
"react-dom": "^19.0.0",
"react-hook-form": "^7.54.2",
"tailwind-merge": "^3.0.0",
"postcss-preset-env": "^10.2.4",
"react": "^19.1.0",
"react-day-picker": "^9.8.0",
"react-dom": "^19.1.0",
"react-hook-form": "^7.60.0",
"tailwind-merge": "^3.3.1",
"tailwindcss-animate": "^1.0.7",
"zod": "^3.24.2"
"zod": "^4.0.5"
},
"devDependencies": {
"@tailwindcss/postcss": "4.1.11",
@@ -37,12 +37,12 @@
"@types/react": "19.1.8",
"@types/react-dom": "19.1.6",
"eslint": "9.31.0",
"eslint-config-next": "15.3.5",
"eslint-config-next": "15.4.1",
"eslint-config-prettier": "10.1.5",
"postcss": "8.5.6",
"tailwindcss": "4.1.11",
"turbo": "2.5.4",
"typescript": "5.8.3"
},
"packageManager": "npm@11.4.2"
"packageManager": "pnpm@10.13.1"
}

6286
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

3
pnpm-workspace.yaml Normal file
View File

@@ -0,0 +1,3 @@
onlyBuiltDependencies:
- '@tailwindcss/oxide'
- sharp

View File

@@ -22,6 +22,6 @@
},
"target": "ES2023"
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "event-dates.json"],
"exclude": ["node_modules"]
}