diff --git a/package.json b/package.json
index 7acc5d1..c40c3ce 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "my-weekly-todo-list",
- "version": "1.51.1",
+ "version": "1.51.2",
"description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view",
"main": "index.js",
"scripts": {
diff --git a/src/app/auth/login/page.tsx b/src/app/auth/login/page.tsx
index 6a1195d..5a31b5d 100644
--- a/src/app/auth/login/page.tsx
+++ b/src/app/auth/login/page.tsx
@@ -11,16 +11,35 @@ function LoginContent() {
const error = searchParams.get('error');
const [isLoading, setIsLoading] = useState(false);
+ const [credError, setCredError] = useState(null);
+
const handleCredentialsSignIn = async (e: React.FormEvent) => {
e.preventDefault();
setIsLoading(true);
+ setCredError(null);
const formData = new FormData(e.currentTarget);
- await signIn('credentials', {
- email: formData.get('email'),
- password: formData.get('password'),
- callbackUrl,
- });
+ try {
+ const result = await signIn('credentials', {
+ email: formData.get('email'),
+ password: formData.get('password'),
+ redirect: false,
+ });
+
+ if (result?.error) {
+ if (result.error === 'CredentialsSignin') {
+ setCredError('Invalid email or password');
+ } else {
+ setCredError(result.error);
+ }
+ setIsLoading(false);
+ } else if (result?.ok) {
+ window.location.href = callbackUrl;
+ }
+ } catch {
+ setCredError('An unexpected error occurred');
+ setIsLoading(false);
+ }
};
const handleGoogleSignIn = () => {
@@ -42,11 +61,15 @@ function LoginContent() {
{/* Error Message */}
- {error && (
+ {(error || credError) && (
- {error === 'CredentialsSignin'
+ {credError
+ ? credError
+ : error === 'CredentialsSignin'
? 'Invalid email or password'
- : 'An error occurred during sign in'}
+ : error === 'email_not_verified'
+ ? 'Please verify your email before signing in'
+ : `An error occurred during sign in (${error})`}
)}
diff --git a/src/components/WeeklyView.tsx b/src/components/WeeklyView.tsx
index dabe474..a8c8294 100644
--- a/src/components/WeeklyView.tsx
+++ b/src/components/WeeklyView.tsx
@@ -1653,22 +1653,22 @@ export default function WeeklyView() {
}
return null;
});
- const resizingRef = useRef<{ target: 'someday' | 'allday'; startY: number; startHeight: number } | null>(null);
+ const resizingRef = useRef<{ target: 'someday' | 'allday'; startY: number; startHeight: number; handleOnTop: boolean } | null>(null);
- const startResize = useCallback((e: React.MouseEvent | React.TouchEvent, target: 'someday' | 'allday') => {
+ const startResize = useCallback((e: React.MouseEvent | React.TouchEvent, target: 'someday' | 'allday', handleOnTop = false) => {
e.preventDefault();
e.stopPropagation();
const clientY = 'touches' in e ? e.touches[0].clientY : e.clientY;
const section = target === 'someday' ? somedaySectionRef.current : (document.querySelector('.all-day-events-section') as HTMLElement);
if (!section) return;
- resizingRef.current = { target, startY: clientY, startHeight: section.getBoundingClientRect().height };
+ resizingRef.current = { target, startY: clientY, startHeight: section.getBoundingClientRect().height, handleOnTop };
const onMove = (ev: MouseEvent | TouchEvent) => {
if (!resizingRef.current) return;
const y = 'touches' in ev ? ev.touches[0].clientY : ev.clientY;
const rawDelta = y - resizingRef.current.startY;
// Top handle: dragging up = increase height (invert delta); bottom handle: normal
- const delta = resizingRef.current.target === 'someday' ? -rawDelta : rawDelta;
+ const delta = resizingRef.current.handleOnTop ? -rawDelta : rawDelta;
const newHeight = Math.max(40, Math.min(600, resizingRef.current.startHeight + delta));
if (resizingRef.current.target === 'someday') setSomedayHeight(newHeight);
else setAllDayHeight(newHeight);
@@ -5411,8 +5411,20 @@ export default function WeeklyView() {
);
if (allDayEvents.length === 0) return null;
+ const handleOnTop = effectiveAllDayPosition === "below";
+ const resizeHandle = isAllDayExpanded ? (
+ startResize(e, 'allday', handleOnTop)}
+ onTouchStart={(e) => startResize(e, 'allday', handleOnTop)}
+ >
+
+
+ ) : null;
+
return (
<>
+ {effectiveAllDayPosition === "below" && resizeHandle}
- {/* Resize handle - outside section so it's always at the bottom border */}
- {isAllDayExpanded && (
- startResize(e, 'allday')}
- onTouchStart={(e) => startResize(e, 'allday')}
- >
-
-
- )}
+ {effectiveAllDayPosition === "above" && resizeHandle}
>
);
})();
@@ -7315,8 +7318,8 @@ export default function WeeklyView() {
{somedayExpanded && (
startResize(e, 'someday')}
- onTouchStart={(e) => startResize(e, 'someday')}
+ onMouseDown={(e) => startResize(e, 'someday', true)}
+ onTouchStart={(e) => startResize(e, 'someday', true)}
>
diff --git a/src/lib/auth.ts b/src/lib/auth.ts
index 9d7c243..e40daa8 100644
--- a/src/lib/auth.ts
+++ b/src/lib/auth.ts
@@ -1,4 +1,5 @@
import { NextAuthOptions } from "next-auth";
+import type { Adapter } from "next-auth/adapters";
import GoogleProvider from "next-auth/providers/google";
import AzureADProvider from "next-auth/providers/azure-ad";
import AppleProvider from "next-auth/providers/apple";
@@ -7,8 +8,24 @@ import CredentialsProvider from "next-auth/providers/credentials";
import { compare } from "bcryptjs";
import { prisma } from "@/lib/prisma";
+// Wrap PrismaAdapter to prevent session creation for credentials provider
+// (known NextAuth v4 issue: adapter tries to create DB session even with JWT strategy)
+const prismaAdapter = PrismaAdapter(prisma) as Adapter;
+const adapter: Adapter = {
+ ...prismaAdapter,
+ createUser: prismaAdapter.createUser,
+ getUser: prismaAdapter.getUser,
+ getUserByEmail: prismaAdapter.getUserByEmail,
+ getUserByAccount: prismaAdapter.getUserByAccount,
+ linkAccount: prismaAdapter.linkAccount,
+ createSession: () => { return null as any; },
+ getSessionAndUser: () => { return null as any; },
+ updateSession: () => { return null as any; },
+ deleteSession: () => { return null as any; },
+};
+
export const authOptions: NextAuthOptions = {
- adapter: PrismaAdapter(prisma),
+ adapter,
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID || "",