将next-auth替换为better-auth

This commit is contained in:
2025-12-10 17:54:14 +08:00
parent db96b86e65
commit 881d9ca921
45 changed files with 2225 additions and 623 deletions

View File

@@ -1,13 +1,13 @@
"use client";
import { useEffect, useState } from "react";
import { useState } from "react";
import LightButton from "@/components/buttons/LightButton";
import { useAudioPlayer } from "@/hooks/useAudioPlayer";
import { getTTSAudioUrl } from "@/lib/browser/tts";
import { VOICES } from "@/config/locales";
import { useTranslations } from "next-intl";
import localFont from "next/font/local";
import { isNonNegativeInteger } from "@/lib/utils";
import { isNonNegativeInteger, SeededRandom } from "@/lib/utils";
import { Pair } from "../../../../generated/prisma/browser";
const myFont = localFont({
@@ -27,20 +27,16 @@ const Memorize: React.FC<MemorizeProps> = ({ textPairs }) => {
const [show, setShow] = useState<"question" | "answer">("question");
const { load, play } = useAudioPlayer();
const [disorderedTextPairs, setDisorderedTextPairs] = useState<Pair[]>(
[],
);
if (textPairs.length === 0) {
return <p>{t("noTextPairs")}</p>;
}
useEffect(() => {
setDisorderedTextPairs(textPairs.toSorted(() => Math.random() - 0.5));
}, [textPairs]);
const rng = new SeededRandom(textPairs[0].folderId);
const disorderedTextPairs = textPairs.toSorted(() => rng.next() - 0.5);
const getTextPairs = () => {
if (disorder) {
return disorderedTextPairs;
}
return textPairs.toSorted((a, b) => a.id - b.id);
};
textPairs.sort((a, b) => a.id - b.id);
const getTextPairs = () => disorder ? disorderedTextPairs : textPairs;
return (
<>
@@ -120,7 +116,7 @@ const Memorize: React.FC<MemorizeProps> = ({ textPairs }) => {
(v) =>
v.locale ===
getTextPairs()[newIndex][
reverse ? "locale2" : "locale1"
reverse ? "locale2" : "locale1"
],
)!.short_name,
).then((url) => {

View File

@@ -1,51 +1,51 @@
"use server";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import {
getFoldersWithTotalPairsByUserId,
getUserIdByFolderId,
} from "@/lib/actions/services/folderService";
} from "@/lib/server/services/folderService";
import { isNonNegativeInteger } from "@/lib/utils";
import FolderSelector from "./FolderSelector";
import Memorize from "./Memorize";
import { getPairsByFolderId } from "@/lib/actions/services/pairService";
import { getPairsByFolderId } from "@/lib/server/services/pairService";
import { auth } from "@/auth";
import { headers } from "next/headers";
export default async function MemorizePage({
searchParams,
}: {
searchParams: Promise<{ folder_id?: string }>;
searchParams: Promise<{ folder_id?: string; }>;
}) {
const session = await auth();
const userId = session?.user?.id;
const session = await auth.api.getSession({ headers: await headers() });
const tParam = (await searchParams).folder_id;
if (!session) {
redirect(
`/login?redirect=/memorize${(await searchParams).folder_id
? `?folder_id=${tParam}`
: ""
}`,
);
}
const t = await getTranslations("memorize.page");
const tParam = (await searchParams).folder_id;
const folder_id = tParam
? isNonNegativeInteger(tParam)
? parseInt(tParam)
: null
: null;
if (!userId) {
redirect(
`/login?redirect=/memorize${folder_id ? `?folder_id=${folder_id}` : ""}`,
);
}
const uid = Number(userId);
if (!folder_id) {
return (
<FolderSelector
folders={await getFoldersWithTotalPairsByUserId(uid)}
folders={await getFoldersWithTotalPairsByUserId(session.user.id)}
/>
);
}
const owner = await getUserIdByFolderId(folder_id);
if (owner !== uid) {
if (owner !== session.user.id) {
return <p>{t("unauthorized")}</p>;
}

View File

@@ -1,4 +1,4 @@
import { useState, useRef, forwardRef, useEffect } from "react";
import { useState, useRef, forwardRef, useEffect, useCallback } from "react";
import SubtitleDisplay from "./SubtitleDisplay";
import LightButton from "@/components/buttons/LightButton";
import { getIndex, parseSrt, getNearistIndex } from "../subtitle";
@@ -20,7 +20,7 @@ const VideoPanel = forwardRef<HTMLVideoElement, VideoPanelProps>(
const [spanText, setSpanText] = useState<string>("");
const [subtitle, setSubtitle] = useState<string>("");
const parsedSrtRef = useRef<
{ start: number; end: number; text: string }[] | null
{ start: number; end: number; text: string; }[] | null
>(null);
const rafldRef = useRef<number>(0);
const ready = useRef({
@@ -31,7 +31,7 @@ const VideoPanel = forwardRef<HTMLVideoElement, VideoPanelProps>(
},
});
const togglePlayPause = () => {
const togglePlayPause = useCallback(() => {
if (!videoUrl) return;
const video = videoRef.current;
@@ -42,7 +42,7 @@ const VideoPanel = forwardRef<HTMLVideoElement, VideoPanelProps>(
video.pause();
}
setIsPlaying(!video.paused);
}
}, [videoRef, videoUrl]);
useEffect(() => {
const handleKeyDownEvent = (e: globalThis.KeyboardEvent) => {

View File

@@ -16,7 +16,7 @@ import { VOICES } from "@/config/locales";
import { useTranslations } from "next-intl";
import { getLocalStorageOperator } from "@/lib/browser/localStorageOperators";
import { getTTSAudioUrl } from "@/lib/browser/tts";
import { genIPA, genLocale } from "@/lib/actions/translatorActions";
import { genIPA, genLocale } from "@/lib/server/translatorActions";
export default function TextSpeakerPage() {
const t = useTranslations("text_speaker");

View File

@@ -1,15 +1,17 @@
"use client";
import LightButton from "@/components/buttons/LightButton";
import Container from "@/components/cards/Container";
import { TranslationHistorySchema } from "@/lib/interfaces";
import { useSession } from "next-auth/react";
import { Dispatch, useEffect, useState } from "react";
import z from "zod";
import { Folder } from "../../../../generated/prisma/browser";
import { getFoldersByUserId } from "@/lib/actions/services/folderService";
import { getFoldersByUserId } from "@/lib/server/services/folderService";
import { Folder as Fd } from "lucide-react";
import { createPair } from "@/lib/actions/services/pairService";
import { createPair } from "@/lib/server/services/pairService";
import { toast } from "sonner";
import { useTranslations } from "next-intl";
import { authClient } from "@/lib/auth-client";
interface AddToFolderProps {
item: z.infer<typeof TranslationHistorySchema>;
@@ -17,19 +19,21 @@ interface AddToFolderProps {
}
const AddToFolder: React.FC<AddToFolderProps> = ({ item, setShow }) => {
const session = useSession();
const { data: session } = authClient.useSession();
const [folders, setFolders] = useState<Folder[]>([]);
const t = useTranslations("translator.add_to_folder");
const [loading, setLoading] = useState(true);
useEffect(() => {
const userId = Number(session.data!.user!.id);
if (!session) return;
const userId = session.user.id;
getFoldersByUserId(userId)
.then(setFolders)
.then(() => setLoading(false));
}, [session.data]);
}, [session]);
if (session.status !== "authenticated") {
if (!session) {
return (
<div className="fixed left-0 top-0 z-50 w-screen h-screen bg-black/50 flex justify-center items-center">
<Container className="p-6">

View File

@@ -1,13 +1,13 @@
import Container from "@/components/cards/Container";
import { useEffect, useState } from "react";
import { Folder } from "../../../../generated/prisma/browser";
import { getFoldersByUserId } from "@/lib/actions/services/folderService";
import { getFoldersByUserId } from "@/lib/server/services/folderService";
import LightButton from "@/components/buttons/LightButton";
import { Folder as Fd } from "lucide-react";
interface FolderSelectorProps {
setSelectedFolderId: (id: number) => void;
userId: number;
userId: string;
cancel: () => void;
}

View File

@@ -17,18 +17,16 @@ import {
genIPA,
genLocale,
genTranslation,
} from "@/lib/actions/translatorActions";
} from "@/lib/server/translatorActions";
import { toast } from "sonner";
import FolderSelector from "./FolderSelector";
import { useSession } from "next-auth/react";
import { createPair } from "@/lib/actions/services/pairService";
import { createPair } from "@/lib/server/services/pairService";
import { shallowEqual } from "@/lib/utils";
import { authClient } from "@/lib/auth-client";
export default function TranslatorPage() {
const t = useTranslations("translator");
const session = useSession();
const taref = useRef<HTMLTextAreaElement>(null);
const [lang, setLang] = useState<string>("chinese");
const [tresult, setTresult] = useState<string>("");
@@ -49,8 +47,9 @@ export default function TranslatorPage() {
});
const [autoSave, setAutoSave] = useState(false);
const [autoSaveFolderId, setAutoSaveFolderId] = useState<number | null>(null);
const { data: session } = authClient.useSession();
useEffect(()=>{
useEffect(() => {
setHistory(tlso.get());
}, []);
@@ -310,7 +309,7 @@ export default function TranslatorPage() {
checked={autoSave}
onChange={(e) => {
const checked = e.target.checked;
if (checked === true && !(session.status === "authenticated")) {
if (checked === true && !session) {
toast.warning("Please login to enable auto-save");
return;
}
@@ -368,7 +367,7 @@ export default function TranslatorPage() {
)}
{autoSave && !autoSaveFolderId && (
<FolderSelector
userId={Number(session.data!.user!.id)}
userId={session!.user.id as string}
cancel={() => setAutoSave(false)}
setSelectedFolderId={(id) => setAutoSaveFolderId(id)}
/>