Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
cf9a83a
Update issue templates
jzgom067 Oct 29, 2025
bc3611e
format not-found page
mirmirmirr Nov 1, 2025
1461efb
Update not-found.tsx
mirmirmirr Nov 1, 2025
4867ec4
add function to handle API errors
mirmirmirr Nov 1, 2025
3c40f1d
bubble up GET api errors
mirmirmirr Nov 1, 2025
fd0ca34
update handle error file
mirmirmirr Nov 1, 2025
9cdfd87
update imports for fetch-data
mirmirmirr Nov 1, 2025
099ca37
resolve import errors
mirmirmirr Nov 1, 2025
24e73d6
Update page.tsx
mirmirmirr Nov 1, 2025
142ae3a
Merge branch 'main-preview' into error-handling
mirmirmirr Nov 2, 2025
787de24
refactor text-input-field
mirmirmirr Nov 2, 2025
c511b78
add error handling to login page
mirmirmirr Nov 2, 2025
7914b97
add rate limit error and limit toasts to only api errors
mirmirmirr Nov 2, 2025
45caa7e
create banner component
mirmirmirr Nov 2, 2025
3aab67e
Update page.tsx
mirmirmirr Nov 3, 2025
358e0b0
Merge branch 'main-preview' into error-handling
mirmirmirr Nov 3, 2025
b59c0ed
update login page catch block
mirmirmirr Nov 3, 2025
dc8a99d
add toasts to register page
mirmirmirr Nov 3, 2025
c11abeb
handle register api response erorr
mirmirmirr Nov 3, 2025
6b5bc67
add rate limit banner to register page
mirmirmirr Nov 3, 2025
0ee72fc
add error handling for password check api
mirmirmirr Nov 3, 2025
4b40c22
update notfound page to be more generic
mirmirmirr Nov 3, 2025
8d3daf4
add rate limit to forgot password page
mirmirmirr Nov 3, 2025
354890b
add toasts to reset password
mirmirmirr Nov 3, 2025
8e3b97b
replace event name field with text input field
mirmirmirr Nov 3, 2025
4c80c19
move text-input-field to global components
mirmirmirr Nov 3, 2025
dd76851
Update text-input-field.tsx
mirmirmirr Nov 3, 2025
42a47bd
add error ui for event editor page
mirmirmirr Nov 3, 2025
cf73b9d
add rate limit banner to availablity page
mirmirmirr Nov 3, 2025
5c4ab5f
remove alerts from email sent page
mirmirmirr Nov 3, 2025
b3d5ac2
remove alerts from verify email page
mirmirmirr Nov 3, 2025
a6b625d
remove alerts from account dropdown
mirmirmirr Nov 3, 2025
9474783
pass new input value in for custom code
mirmirmirr Nov 3, 2025
cf0ae10
adjust validation blocks for specific day event
mirmirmirr Nov 3, 2025
bf93ebc
remove duplicate formatApiError call
mirmirmirr Nov 3, 2025
7e1c14f
remove setting verify variables
mirmirmirr Nov 3, 2025
25be3a6
remove unused import
mirmirmirr Nov 3, 2025
349282b
add use-debounce library
mirmirmirr Nov 4, 2025
e911993
use debounce on painting page
mirmirmirr Nov 4, 2025
ff2f9db
Update page-client.tsx
mirmirmirr Nov 4, 2025
1f37477
add use debounce to custom code check
mirmirmirr Nov 4, 2025
39ed9a7
return debounce it customCode is none
mirmirmirr Nov 4, 2025
ce7dda5
make debounce async
mirmirmirr Nov 4, 2025
1b8e8f8
Merge pull request #82 from plan-cake/use-debounce
mirmirmirr Nov 4, 2025
72f72dd
fix isSelected error
mirmirmirr Nov 4, 2025
90a1213
Update src/features/event/editor/editor.tsx
mirmirmirr Nov 13, 2025
d558e0d
Update src/app/(auth)/forgot-password/page.tsx
mirmirmirr Nov 13, 2025
db0ea42
replace old useDebounce in reset-password
mirmirmirr Nov 13, 2025
5eb5f45
add refined error messages
mirmirmirr Nov 13, 2025
b437f4f
restore concentric circles
mirmirmirr Nov 13, 2025
14fb8f1
disable editing code
mirmirmirr Nov 13, 2025
982a817
Update fetch-data.ts
mirmirmirr Nov 13, 2025
d5feb8f
create and integrate TOAST_MESSAGES
mirmirmirr Nov 14, 2025
a05c3f0
add periods
mirmirmirr Nov 15, 2025
824a2b3
add aria hidden to icon
mirmirmirr Nov 15, 2025
7ad1895
add toast messages to register page
mirmirmirr Nov 15, 2025
12f52c7
Update page.tsx
mirmirmirr Nov 15, 2025
f29f073
add event duration variable
mirmirmirr Nov 15, 2025
ca4551b
rename TOAST_MESSAGES to MESSAGES
mirmirmirr Nov 15, 2025
24ed137
adjust the label spacing
mirmirmirr Nov 15, 2025
818fe1e
remove period
mirmirmirr Nov 15, 2025
e4b1663
create constant for title length
mirmirmirr Dec 29, 2025
61c7e4e
create universal error hook
mirmirmirr Dec 29, 2025
82e158b
create rate limit banner
mirmirmirr Dec 29, 2025
665158c
add token error message
mirmirmirr Dec 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"react-select": "^5.10.2",
"react-timezone-select": "^3.2.8",
"tailwind-merge": "^3.2.0",
"use-debounce": "^10.0.6",
"vaul": "^1.1.2"
},
"devDependencies": {
Expand Down
48 changes: 40 additions & 8 deletions src/app/(auth)/forgot-password/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,39 @@ import { useState } from "react";

import Link from "next/link";

import RateLimitBanner from "@/components/banner/rate-limit";
import MessagePage from "@/components/layout/message-page";
import LinkText from "@/components/link-text";
import TextInputField from "@/features/auth/components/text-input-field";
import TextInputField from "@/components/text-input-field";
import ActionButton from "@/features/button/components/action";
import LinkButton from "@/features/button/components/link";
import formatApiError from "@/lib/utils/api/format-api-error";
import { useFormErrors } from "@/lib/hooks/use-form-errors";
import { MESSAGES } from "@/lib/messages";
import { formatApiError } from "@/lib/utils/api/handle-api-error";

export default function Page() {
const [email, setEmail] = useState("");
const [emailSent, setEmailSent] = useState(false);

// TOASTS AND ERROR STATES
const { errors, handleError, clearAllErrors, handleGenericError } =
useFormErrors();

const handleEmailChange = (value: string) => {
handleError("email", "");
handleError("api", "");
setEmail(value);
};

const stopRefresh = (e: React.FormEvent) => {
e.preventDefault();
};

const handleSubmit = async () => {
clearAllErrors();

if (!email) {
alert("Missing email");
handleError("email", MESSAGES.ERROR_EMAIL_MISSING);
return false;
}

Expand All @@ -36,18 +51,27 @@ export default function Page() {
setEmailSent(true);
return true;
} else {
alert(formatApiError(await res.json()));
const body = await res.json();
const errorMessage = formatApiError(body);

if (res.status === 429) {
handleError("rate_limit", errorMessage);
} else if (errorMessage.includes("Email:")) {
handleError("email", errorMessage.split("Email:")[1].trim());
} else {
handleError("api", errorMessage);
}
return false;
}
} catch (err) {
console.error("Fetch error:", err);
alert("An error occurred. Please try again.");
handleGenericError();
return false;
}
};

return (
<div className="flex h-screen items-center justify-center">
<div className="flex h-screen flex-col items-center justify-center gap-4">
{emailSent ? (
<MessagePage
title="Check your email"
Expand All @@ -71,12 +95,20 @@ export default function Page() {
forgot password
</h1>

{/* Rate Limit Error */}
{errors.rate_limit && (
<RateLimitBanner>{errors.rate_limit}</RateLimitBanner>
)}

{/* Email */}
<TextInputField
id={"email"}
type="email"
placeholder="Email"
label="Email*"
value={email}
onChange={setEmail}
onChange={handleEmailChange}
outlined
error={errors.email || errors.api}
/>

<div className="flex w-full items-center justify-between">
Expand Down
66 changes: 55 additions & 11 deletions src/app/(auth)/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ import React, { useContext, useState } from "react";
import Link from "next/link";
import { useRouter } from "next/navigation";

import RateLimitBanner from "@/components/banner/rate-limit";
import Checkbox from "@/components/checkbox";
import LinkText from "@/components/link-text";
import TextInputField from "@/features/auth/components/text-input-field";
import TextInputField from "@/components/text-input-field";
import ActionButton from "@/features/button/components/action";
import { useFormErrors } from "@/lib/hooks/use-form-errors";
import { MESSAGES } from "@/lib/messages";
import { LoginContext } from "@/lib/providers";
import formatApiError from "@/lib/utils/api/format-api-error";
import { formatApiError } from "@/lib/utils/api/handle-api-error";

export default function Page() {
const [email, setEmail] = useState("");
Expand All @@ -19,17 +22,35 @@ export default function Page() {
const { setLoggedIn } = useContext(LoginContext);
const router = useRouter();

// TOASTS AND ERROR STATES
const { errors, handleError, clearAllErrors, handleGenericError } =
useFormErrors();

const handleEmailChange = (value: string) => {
handleError("email", "");
handleError("api", "");
setEmail(value);
};

const handlePasswordChange = (value: string) => {
handleError("password", "");
handleError("api", "");
setPassword(value);
};

const stopRefresh = (e: React.FormEvent) => {
e.preventDefault();
};

const handleSubmit = async () => {
clearAllErrors();

if (!email) {
alert("Missing email");
handleError("email", MESSAGES.ERROR_EMAIL_MISSING);
return false;
}
if (!password) {
alert("Missing password");
handleError("password", MESSAGES.ERROR_PASSWORD_MISSING);
return false;
}

Expand All @@ -45,38 +66,61 @@ export default function Page() {
router.push("/dashboard");
return true;
} else {
alert(formatApiError(await res.json()));
const body = await res.json();

const errorMessage = formatApiError(body);

if (res.status === 429) {
handleError("rate_limit", errorMessage);
} else if (errorMessage.includes("Email:")) {
handleError("email", errorMessage.split("Email:")[1].trim());
} else if (errorMessage.includes("Password:")) {
handleError("password", errorMessage.split("Password:")[1].trim());
} else {
handleError("api", errorMessage);
}
return false;
}
} catch (err) {
console.error("Fetch error:", err);
alert("An error occurred. Please try again.");
handleGenericError();
return false;
}
};

return (
<div className="flex h-screen items-center justify-center">
<div className="flex h-screen flex-col items-center justify-center gap-4">
<form onSubmit={stopRefresh} className="flex w-80 flex-col items-center">
{/* Title */}
<h1 className="font-display text-lion mb-4 block text-5xl leading-none md:text-8xl">
login
</h1>

{/* Rate Limit Error */}
{errors.rate_limit && (
<RateLimitBanner>{errors.rate_limit}</RateLimitBanner>
)}

{/* Email */}
<TextInputField
id={"email"}
type="email"
placeholder="Email"
label="Email*"
value={email}
onChange={setEmail}
onChange={handleEmailChange}
outlined
error={errors.email || errors.api}
/>

{/* Password */}
<TextInputField
id={"password"}
type="password"
placeholder="Password"
label="Password*"
value={password}
onChange={setPassword}
onChange={handlePasswordChange}
outlined
error={errors.password || errors.api}
/>

<div className="flex w-full items-start justify-between">
Expand Down
18 changes: 13 additions & 5 deletions src/app/(auth)/register/email-sent/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,18 @@ import { useRouter } from "next/navigation";
import MessagePage from "@/components/layout/message-page";
import ActionButton from "@/features/button/components/action";
import LinkButton from "@/features/button/components/link";
import formatApiError from "@/lib/utils/api/format-api-error";
import { useToast } from "@/features/toast/context";
import { MESSAGES } from "@/lib/messages";
import { formatApiError } from "@/lib/utils/api/handle-api-error";

export default function Page() {
const router = useRouter();
const lastEmailResend = useRef(Date.now());
const [email, setEmail] = useState("");

// TOASTS AND ERROR STATES
const { addToast } = useToast();

useEffect(() => {
const storedEmail = sessionStorage.getItem("register_email");
if (!storedEmail) {
Expand All @@ -37,7 +42,10 @@ export default function Page() {
(emailResendCooldown - (Date.now() - lastEmailResend.current)) / 1000;
timeLeft = Math.ceil(timeLeft);
if (timeLeft > 0) {
alert(`Slow down! ${timeLeft} seconds until you can send again.`);
addToast(
"info",
`Slow down! ${timeLeft} seconds until you can send again.`,
);
return false;
}

Expand All @@ -49,16 +57,16 @@ export default function Page() {
});

if (res.ok) {
alert("Email resent. Please check your inbox.");
addToast("success", MESSAGES.SUCCESS_EMAIL_SENT);
lastEmailResend.current = Date.now();
return true;
} else {
alert(formatApiError(await res.json()));
addToast("error", formatApiError(await res.json()));
return false;
}
} catch (err) {
console.error("Fetch error:", err);
alert("An error occurred. Please try again.");
addToast("error", MESSAGES.ERROR_GENERIC);
return false;
}
};
Expand Down
Loading
Loading