mirror of https://gitee.com/answerdev/answer.git
fix: detail page render 404
This commit is contained in:
parent
0566894a2c
commit
450b7c03b9
|
@ -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 }}>
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
.page-wrap {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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 />
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 },
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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;
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue