fix: detail page render 404

This commit is contained in:
shuai 2023-02-27 10:45:48 +08:00
parent 0566894a2c
commit 450b7c03b9
11 changed files with 99 additions and 22 deletions

View File

@ -1,11 +1,25 @@
import { useEffect } from 'react';
import { Container, Button } from 'react-bootstrap';
import { Link } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import './index.scss';
const Index = () => {
const { t } = useTranslation('translation', { keyPrefix: 'page_404' });
useEffect(() => {
// auto height of container
const pageWrap = document.querySelector('.page-wrap');
pageWrap.style.display = 'contents';
return () => {
pageWrap.style.display = 'block';
};
}, []);
return (
<Container className="d-flex flex-column justify-content-center align-items-center page-wrap">
<Container
className="d-flex flex-column justify-content-center align-items-center"
style={{ flex: 1 }}>
<div
className="mb-4 text-secondary"
style={{ fontSize: '120px', lineHeight: 1.2 }}>

View File

@ -0,0 +1,4 @@
.page-wrap {
display: flex;
flex: 1;
}

View File

@ -1,9 +1,19 @@
import { useEffect } from 'react';
import { Container, Button } from 'react-bootstrap';
import { Link } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
const Index = () => {
const { t } = useTranslation('translation', { keyPrefix: 'page_50X' });
useEffect(() => {
// auto height of container
const pageWrap = document.querySelector('.page-wrap');
pageWrap.style.display = 'contents';
return () => {
pageWrap.style.display = 'block';
};
}, []);
return (
<Container className="d-flex flex-column justify-content-center align-items-center page-wrap">
<div

View File

@ -1,10 +1,10 @@
import { FC, memo } from 'react';
import { Outlet } from 'react-router-dom';
import { FC, memo, useEffect } from 'react';
import { Outlet, useLocation } from 'react-router-dom';
import { HelmetProvider } from 'react-helmet-async';
import { SWRConfig } from 'swr';
import { toastStore, loginToContinueStore } from '@/stores';
import { toastStore, loginToContinueStore, notFoundStore } from '@/stores';
import {
Header,
Footer,
@ -15,14 +15,22 @@ import {
} from '@/components';
import { LoginToContinueModal } from '@/components/Modal';
import { useImgViewer } from '@/hooks';
import Component404 from '@/pages/404';
const Layout: FC = () => {
const location = useLocation();
const { msg: toastMsg, variant, clear: toastClear } = toastStore();
const closeToast = () => {
toastClear();
};
const { visible: show404, hide: notFoundHide } = notFoundStore();
const imgViewer = useImgViewer();
const { show: showLoginToContinueModal } = loginToContinueStore();
useEffect(() => {
notFoundHide();
}, [location]);
return (
<HelmetProvider>
<PageTags />
@ -36,7 +44,7 @@ const Layout: FC = () => {
<div
className="position-relative page-wrap"
onClick={imgViewer.checkClickForImgView}>
<Outlet />
{show404 ? <Component404 /> : <Outlet />}
</div>
<Toast msg={toastMsg} variant={variant} onClose={closeToast} />
<Footer />

View File

@ -11,6 +11,7 @@ import {
usePersonalTop,
usePersonalListByTabName,
} from '@/services';
import type { UserInfoRes } from '@/common/interface';
import {
UserInfo,
@ -47,8 +48,8 @@ const Personal: FC = () => {
tabName,
);
let pageTitle = '';
if (userInfo && userInfo.info && userInfo.has) {
pageTitle = `${userInfo.info.display_name} (${userInfo.info.username})`;
if (userInfo?.username) {
pageTitle = `${userInfo?.display_name} (${userInfo?.username})`;
}
const { count = 0, list = [] } = listData?.[tabName] || {};
usePageTags({
@ -57,11 +58,11 @@ const Personal: FC = () => {
return (
<Container className="pt-4 mt-2 mb-5">
<Row className="justify-content-center">
{userInfo?.info?.status !== 'normal' && userInfo?.info?.status_msg && (
<Alert data={userInfo?.info.status_msg} />
{userInfo?.status !== 'normal' && userInfo?.status_msg && (
<Alert data={userInfo?.status_msg} />
)}
<Col xxl={7} lg={8} sm={12}>
<UserInfo data={userInfo?.info} />
<UserInfo data={userInfo as UserInfoRes} />
</Col>
<Col
xxl={3}
@ -88,11 +89,11 @@ const Personal: FC = () => {
<Col xxl={7} lg={8} sm={12}>
<Overview
visible={tabName === 'overview'}
introduction={userInfo?.info?.bio_html}
introduction={userInfo?.bio_html || ''}
data={topData}
/>
<ListHead
count={tabName === 'reputation' ? userInfo?.info?.rank : count}
count={tabName === 'reputation' ? Number(userInfo?.rank) : count}
sort={order}
visible={tabName !== 'overview'}
tabName={tabName}
@ -120,17 +121,14 @@ const Personal: FC = () => {
</Col>
<Col xxl={3} lg={4} sm={12} className="mt-5 mt-lg-0">
<h5 className="mb-3">{t('stats')}</h5>
{userInfo?.info && (
{userInfo?.created_at && (
<>
<div className="text-secondary">
<FormatTime
time={userInfo.info.created_at}
preFix={t('joined')}
/>
<FormatTime time={userInfo.created_at} preFix={t('joined')} />
</div>
<div className="text-secondary">
<FormatTime
time={userInfo.info.last_login_date}
time={userInfo.last_login_date}
preFix={t('last_login')}
/>
</div>

View File

@ -8,7 +8,10 @@ export const usePersonalInfoByName = (username: string) => {
const apiUrl = '/answer/api/v1/personal/user/info';
const { data, error, mutate } = useSWR<Type.UserInfoRes, Error>(
username ? `${apiUrl}?username=${username}` : null,
request.instance.get,
(url) =>
request.get(url, {
allow404: true,
}),
);
return {
data,

View File

@ -47,7 +47,9 @@ export const useTagInfo = ({ id = '', name = '' }) => {
name = encodeURIComponent(name);
apiUrl = `/answer/api/v1/tag?name=${name}`;
}
const { data, error } = useSWR<Type.TagInfo>(apiUrl, request.instance.get);
const { data, error } = useSWR<Type.TagInfo>(apiUrl, (url) =>
request.get(url, { allow404: true }),
);
return {
data,
isLoading: !data && !error,

View File

@ -171,6 +171,7 @@ export const saveQuestion = (params: Type.QuestionParams) => {
export const questionDetail = (id: string) => {
return request.get<Type.QuestionDetailRes>(
`/answer/api/v1/question/info?id=${id}`,
{ allow404: true },
);
};

View File

@ -10,6 +10,7 @@ import pageTagStore from './pageTags';
import customizeStore from './customize';
import themeSettingStore from './themeSetting';
import loginToContinueStore from './loginToContinue';
import notFoundStore from './notFound';
export {
toastStore,
@ -23,4 +24,5 @@ export {
themeSettingStore,
seoSettingStore,
loginToContinueStore,
notFoundStore,
};

23
ui/src/stores/notFound.ts Normal file
View File

@ -0,0 +1,23 @@
import create from 'zustand';
interface NotFoundType {
visible: boolean;
show: () => void;
hide: () => void;
}
const notFound = create<NotFoundType>((set) => ({
visible: false,
show: () => {
set(() => {
return { visible: true };
});
},
hide: () => {
set(() => {
return { visible: false };
});
},
}));
export default notFound;

View File

@ -2,7 +2,7 @@ import axios, { AxiosResponse } from 'axios';
import type { AxiosInstance, AxiosRequestConfig, AxiosError } from 'axios';
import { Modal } from '@/components';
import { loggedUserInfoStore, toastStore } from '@/stores';
import { loggedUserInfoStore, toastStore, notFoundStore } from '@/stores';
import { LOGGED_TOKEN_STORAGE_KEY } from '@/common/constants';
import { RouteAlias } from '@/router/alias';
import { getCurrentLang } from '@/utils/localize';
@ -15,6 +15,10 @@ const baseConfig = {
withCredentials: true,
};
interface APIconfig extends AxiosRequestConfig {
allow404: boolean;
}
class Request {
instance: AxiosInstance;
@ -49,6 +53,9 @@ class Request {
(error) => {
const { status, data: respData } = error.response || {};
const { data = {}, msg = '', reason = '' } = respData || {};
console.log('response error:', error);
if (status === 400) {
// show error message
if (data instanceof Object && data.err_type) {
@ -135,6 +142,11 @@ class Request {
}
return Promise.reject(false);
}
if (status === 404 && error.config?.allow404) {
notFoundStore.getState().show();
return Promise.reject(false);
}
if (status >= 500) {
console.error(
`Request failed with status code ${status}, ${msg || ''}`,
@ -149,7 +161,7 @@ class Request {
return this.instance.request(config);
}
public get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
public get<T = any>(url: string, config?: APIconfig): Promise<T> {
return this.instance.get(url, config);
}