feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
/* stylelint-disable declaration-no-important -- 历史代码,为避免引入新BUG暂不修复 */
|
||||
.wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
margin: auto;
|
||||
padding-top: 35.39vh;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-top: 24px !important;
|
||||
margin-bottom: 4px !important;
|
||||
|
||||
font-size: 16px !important;
|
||||
font-weight: 600 !important;
|
||||
line-height: 22px !important;
|
||||
}
|
||||
|
||||
.paragraph {
|
||||
margin-bottom: 8px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: #1d1c2399;
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useNavigate, useRouteError } from 'react-router-dom';
|
||||
import { useMemo, useState, type FC } from 'react';
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { escape } from 'lodash-es';
|
||||
import { BaseEnum } from '@coze-arch/web-context';
|
||||
import { getSlardarInstance } from '@coze-arch/logger';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Typography, UIButton } from '@coze-arch/bot-semi';
|
||||
import { useRouteConfig } from '@coze-arch/bot-hooks';
|
||||
import { isCustomError, useRouteErrorCatch } from '@coze-arch/bot-error';
|
||||
import { IllustrationNoAccess } from '@douyinfe/semi-illustrations';
|
||||
import { useSpaceStore, useSpaceApp } from '@coze-foundation/space-store';
|
||||
|
||||
import s from './index.module.less';
|
||||
|
||||
// i18n 的配置,对齐 starling 文案后再替换
|
||||
export const GlobalError: FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const spaceApp = useSpaceApp();
|
||||
const { menuKey: base } = useRouteConfig();
|
||||
const { id, getPersonalSpaceID } = useSpaceStore(
|
||||
useShallow(spaceStore => ({
|
||||
id: spaceStore.space.id,
|
||||
getPersonalSpaceID: spaceStore.getPersonalSpaceID,
|
||||
})),
|
||||
);
|
||||
const error = useRouteError();
|
||||
useRouteErrorCatch(error);
|
||||
|
||||
const isLazyLoadError = useMemo(() => {
|
||||
if (hasErrorMessage(error)) {
|
||||
return /Minified\sReact\serror\s\#306/i.test(error.message);
|
||||
}
|
||||
}, [error]);
|
||||
|
||||
const customGlobalErrorConfig = useMemo(() => {
|
||||
if (isCustomError(error)) {
|
||||
return error.ext?.customGlobalErrorConfig;
|
||||
}
|
||||
}, [error]);
|
||||
|
||||
const [sessionId] = useState(() => getSlardarInstance()?.config()?.sessionId);
|
||||
|
||||
return (
|
||||
<div className={s.wrapper}>
|
||||
<div className={s.content}>
|
||||
<IllustrationNoAccess width={140} height={140} />
|
||||
<Typography.Title className={s.title}>
|
||||
{customGlobalErrorConfig?.title ??
|
||||
I18n.t('errorpage_bot_title', {}, `Failed to view the ${spaceApp}`)}
|
||||
</Typography.Title>
|
||||
<Typography.Paragraph className={s.paragraph}>
|
||||
{customGlobalErrorConfig?.subtitle ??
|
||||
I18n.t(
|
||||
'errorpage_subtitle',
|
||||
{},
|
||||
"Please check your link or try again after joining the bot's team.",
|
||||
)}
|
||||
</Typography.Paragraph>
|
||||
{!!sessionId && (
|
||||
<div className="leading-[12px] mb-[24px] text-[12px] text-gray-400">
|
||||
{sessionId}
|
||||
</div>
|
||||
)}
|
||||
<UIButton
|
||||
theme="solid"
|
||||
onClick={() => {
|
||||
let url = '';
|
||||
if (BaseEnum.Space === base) {
|
||||
const spaceId =
|
||||
id ??
|
||||
getPersonalSpaceID() ??
|
||||
// 企业下无个人空间,缺省跳转到第一个空间
|
||||
useSpaceStore.getState().spaceList[0]?.id;
|
||||
url = spaceId ? `/space/${spaceId}/${spaceApp}` : '/space';
|
||||
} else if (base && base in BaseEnum) {
|
||||
url = `/${base}`;
|
||||
} else {
|
||||
url = '/';
|
||||
}
|
||||
|
||||
if (!isLazyLoadError) {
|
||||
navigate(url);
|
||||
} else {
|
||||
window.location.href = escape(url);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{I18n.t('errorpage_bot_btn', {}, 'Go to Bot Platform')}
|
||||
</UIButton>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
function hasErrorMessage(e: unknown): e is { message: string } {
|
||||
if (!e || typeof e !== 'object') {
|
||||
return false;
|
||||
}
|
||||
if ('message' in e && typeof e.message === 'string') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
Reference in New Issue
Block a user