terry-staging #16
@@ -1,25 +1,43 @@
|
|||||||
import { useEffect } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import { useNavigate, useParams } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
import { getJSON } from "../../api";
|
import { getJSON } from "../../api";
|
||||||
import { langQuery, useI18n } from "../../i18n";
|
import { langQuery, useI18n, type Lang } from "../../i18n";
|
||||||
import { useLocalizedPath } from "../../useLocalizedPath";
|
import { useLocalizedPath } from "../../useLocalizedPath";
|
||||||
|
import { localizePath } from "../../languageRoutes";
|
||||||
import { MOCK_POSTS } from "../../mocks/mockPosts";
|
import { MOCK_POSTS } from "../../mocks/mockPosts";
|
||||||
import { POST_STREAM_USES_MOCK } from "../../components/messageStream/hooks/usePostStream";
|
import { POST_STREAM_USES_MOCK } from "../../components/messageStream/hooks/usePostStream";
|
||||||
import { useToast } from "../../components/Toast";
|
import { useToast } from "../../components/Toast";
|
||||||
|
import { Skeleton } from "../../components/Skeleton";
|
||||||
import type { Post } from "../../types/post";
|
import type { Post } from "../../types/post";
|
||||||
|
|
||||||
|
function postLangToUiLang(code: string | undefined): Lang | null {
|
||||||
|
if (!code) return null;
|
||||||
|
const lc = code.trim().toLowerCase();
|
||||||
|
if (lc === "zh" || lc === "zh-cn" || lc === "zh-hans") return "zh-CN";
|
||||||
|
if (lc === "en") return "en";
|
||||||
|
if (lc === "ja") return "ja";
|
||||||
|
if (lc === "ko") return "ko";
|
||||||
|
if (lc === "vi") return "vi";
|
||||||
|
if (lc === "id") return "id";
|
||||||
|
if (lc === "ms") return "ms";
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
export function PostRedirect() {
|
export function PostRedirect() {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const { lang, t } = useI18n();
|
const { lang, t } = useI18n();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const lp = useLocalizedPath();
|
const lp = useLocalizedPath();
|
||||||
const { showToast } = useToast();
|
const { showToast } = useToast();
|
||||||
|
const handledIdRef = useRef<string | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!id) {
|
if (!id) {
|
||||||
navigate(lp("/browse"), { replace: true });
|
navigate(lp("/browse"), { replace: true });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (handledIdRef.current === id) return;
|
||||||
|
handledIdRef.current = id;
|
||||||
|
|
||||||
if (POST_STREAM_USES_MOCK) {
|
if (POST_STREAM_USES_MOCK) {
|
||||||
const post = MOCK_POSTS.find((p) => p.id === id);
|
const post = MOCK_POSTS.find((p) => p.id === id);
|
||||||
@@ -32,25 +50,47 @@ export function PostRedirect() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const goToPost = (post: Post) => {
|
const goToPostInLang = (post: Post, targetLang: Lang) => {
|
||||||
navigate(lp(`/browse?post=${encodeURIComponent(post.id)}`), {
|
navigate(
|
||||||
replace: true,
|
localizePath(`/browse?post=${encodeURIComponent(post.id)}`, targetLang),
|
||||||
});
|
{ replace: true },
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
getJSON<Post>(
|
getJSON<Post>(
|
||||||
`/api/posts/${id}?lang=${encodeURIComponent(langQuery(lang))}`,
|
`/api/posts/${id}?lang=${encodeURIComponent(langQuery(lang))}`,
|
||||||
)
|
)
|
||||||
.then(goToPost)
|
.then((post) => goToPostInLang(post, lang))
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
getJSON<Post>(`/api/posts/${id}`)
|
getJSON<Post>(`/api/posts/${id}`)
|
||||||
.then((post) => {
|
.then((post) => {
|
||||||
|
const sourceLang =
|
||||||
|
postLangToUiLang(post.sourceLanguage) ||
|
||||||
|
postLangToUiLang(post.language) ||
|
||||||
|
lang;
|
||||||
showToast(t("postShownInOriginalLanguage"));
|
showToast(t("postShownInOriginalLanguage"));
|
||||||
goToPost(post);
|
goToPostInLang(post, sourceLang);
|
||||||
})
|
})
|
||||||
.catch(() => navigate(lp("/browse"), { replace: true }));
|
.catch(() => navigate(lp("/browse"), { replace: true }));
|
||||||
});
|
});
|
||||||
}, [id, lang, navigate, lp, showToast, t]);
|
}, [id, lang, navigate, lp, showToast, t]);
|
||||||
|
|
||||||
return <div className="text-neutral-400">…</div>;
|
return (
|
||||||
|
<div
|
||||||
|
aria-live="polite"
|
||||||
|
aria-label={t("loading")}
|
||||||
|
className="mx-auto flex max-w-[1180px] flex-col gap-3 px-4 pt-4 md:px-0 md:pt-2"
|
||||||
|
>
|
||||||
|
{Array.from({ length: 6 }).map((_, i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
className="mx-auto w-full max-w-[358px] md:max-w-[680px] lg:max-w-[900px] xl:max-w-[1120px]"
|
||||||
|
>
|
||||||
|
<Skeleton
|
||||||
|
className={`rounded-2xl ${i % 3 === 0 ? "h-[220px]" : "h-[80px]"}`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user