@blocklet/ui-react
Version:
Some useful front-end web components that can be used in Blocklets.
503 lines (502 loc) • 16.9 kB
JavaScript
import { jsx as r, jsxs as m } from "react/jsx-runtime";
import { use as ke, useMemo as Pe, isValidElement as ie, cloneElement as oe, Children as Se } from "react";
import { Box as a, Typography as B, CircularProgress as Me, Divider as De } from "@mui/material";
import { useMemoizedFn as P, useCreation as d, useRequest as ne } from "ahooks";
import Fe from "p-wait-for";
import se from "react-helmet";
import { SessionContext as Te } from "@arcblock/did-connect-react/lib/Session";
import ze from "@arcblock/ux/lib/Tabs";
import I from "@arcblock/ux/lib/Empty";
import We from "@arcblock/ux/lib/Button";
import Ae from "@arcblock/ux/lib/Result";
import { useConfirm as Le } from "@arcblock/ux/lib/Dialog";
import { translate as Ue } from "@arcblock/ux/lib/Locale/util";
import { useLocaleContext as Be } from "@arcblock/ux/lib/Locale/context";
import { ErrorFallback as Ie } from "@arcblock/ux/lib/ErrorBoundary";
import { styled as pe } from "@arcblock/ux/lib/Theme";
import Ne from "lodash/cloneDeep";
import { joinURL as S, getQuery as je, withoutTrailingSlash as le, withQuery as ae } from "ufo";
import { getBlockletSDK as He } from "@blocklet/js-sdk";
import { isSupportFollow as Ee } from "@arcblock/ux/lib/Util";
import { PROFILE_URL as M } from "@arcblock/ux/lib/Util/constant";
import _e from "../../Footer/index.js";
import ue from "../../Header/index.js";
import { translations as Oe } from "../libs/locales.js";
import de from "./user-info/user-basic-info.js";
import "@mui/icons-material";
import "@iconify/react";
import "@arcblock/ux/lib/DID";
import "@iconify-icons/material-symbols/schedule-outline-rounded";
import "@iconify-icons/material-symbols/more-time-rounded";
import "@iconify-icons/material-symbols/captive-portal-rounded";
import "@iconify-icons/material-symbols/settings-input-antenna-rounded";
import "@arcblock/ux/lib/RelativeTime";
import "@arcblock/ux/lib/UserCard/Content/shorten-label";
import "./user-info/switch-role.js";
import { formatBlockletInfo as Re, getLink as F, getLocalizedNavigation as $e } from "../../blocklets.js";
import qe from "./passport.js";
import Ge from "./settings.js";
import Qe from "../../hooks/use-mobile.js";
import { ConfigUserSpaceProvider as Ke } from "../../contexts/config-user-space.js";
import Ve from "./storage/index.js";
import Je from "./nft.js";
import { UserFollowersProvider as ce } from "../../contexts/user-followers.js";
import Xe from "./fallback.js";
const T = S(M, "/nfts"), z = S(M, "/settings"), W = S(M, "/did-spaces"), j = S(M, "/user-followers"), Ye = (b) => b.some(
(y) => ["/userCenter/nfts", "/userCenter/user-followers", "/userCenter/settings", "/userCenter/did-spaces"].includes(
y.id
) || [T, z, W, j].includes(y.link)
), fe = pe(a)(({ theme: b }) => ({
flex: 1,
boxSizing: "border-box",
padding: "0 16px",
width: "100%",
maxWidth: 1600,
margin: "0 auto",
display: "flex",
alignItems: "stretch",
gap: 2.5,
flexDirection: "column",
[b.breakpoints.up("md")]: {
flexDirection: "row"
}
})), N = pe(a)(({ theme: b }) => ({
overflow: "hidden",
flex: "revert",
[b.breakpoints.up("md")]: {
flex: 1
},
"@media (min-width: 960px) and (max-width: 1050px)": {
"& .user-center-tabs": {
maxWidth: "500px"
}
}
}));
function qr({
children: b,
notLoginContent: y = null,
currentTab: v,
contentProps: H = {},
disableAutoRedirect: E = !1,
hideFooter: me = !1,
headerProps: he = {},
footerProps: xe = {},
userDid: A = void 0,
stickySidebar: _ = !1,
embed: D = !1,
onlyProfile: C = !1,
// 只显示 profile 页面,用于 ArcSphere 只需要显示 Profile 的内容
onDestroySelf: ge = void 0
}) {
const O = He(), { locale: x, defaultLocale: k } = Be(), u = Qe({ key: "md" }), f = P((e, i = {}) => Ue(Oe, e, x, "en", i)), t = ke(Te)?.session, h = d(() => {
if (A)
return A;
const e = window.location.href, i = je(e);
return i?.did ? Array.isArray(i.did) ? i.did[0] : i.did : t?.user?.did;
}, [t?.user?.did, A]), o = d(() => t?.user ? h === t?.user?.did : !1, [h, t?.user?.did]), w = Pe(() => !!t?.user && Ee(), [t?.user]), n = ne(
// eslint-disable-next-line consistent-return
async () => {
if (await Fe(() => t?.initialized), o)
return t.user;
if (h)
return O.user.getUserPublicInfo({ did: h });
},
{
refreshDeps: [h, o, t?.initialized, t?.user]
}
), R = P(() => o ? t.refresh() : n.refresh()), g = ne(
async () => n.data && v ? await O.user.getUserPrivacyConfig({ did: h }) : null,
{
refreshDeps: [h, n.data, v],
loadingDelay: 300
}
), { confirmHolder: $ } = Le({
fullScreen: u,
sx: {
".MuiDialog-paper": {
borderRadius: 1,
maxWidth: 1200
},
".ux-dialog_title": {
fontWeight: 600
},
".ux-dialog_closeButton": {
p: 1
},
".MuiDialogActions-root": {
display: {
xs: "none",
md: "flex"
}
}
}
}), q = d(() => {
const e = Ne(window.blocklet);
try {
return Re(e);
} catch (i) {
return console.error("Failed to format blocklet info", i, e), e;
}
}, []), G = d(() => {
const e = {
label: f("common.nft"),
protected: !1,
isPrivate: !1,
// true: 隐私数据,仅自己可见
value: T,
url: F(T, x, k)
}, i = {
label: f("userFollowers"),
protected: !1,
isPrivate: !1,
value: j,
url: F(j, x, k)
};
let p = w ? [e, i] : [e];
if (o) {
const U = [
e,
{
label: f("common.setting"),
protected: !0,
isPrivate: !0,
value: z,
url: F(z, x, k)
},
{
label: f("storageManagement"),
protected: !0,
isPrivate: !0,
value: W,
url: F(W, x, k)
}
];
p = w ? [...U, i] : U;
}
return p;
}, [o, x, w]), l = d(() => {
const e = q?.navigation?.userCenter || [], i = Ye(e);
return ($e({ navigation: e, locale: x, defaultLocale: k }) || []).concat(i ? [] : G).map((c) => {
const te = c.value ?? c._rawLink ?? c.link ?? c.url;
return {
value: te,
label: c.title || c.label,
url: c.link || c.url,
protected: g?.data?.[te] ?? !1,
isPrivate: c.isPrivate || c.private || (c?._rawLink?.includes("/customer") ?? !1),
// FIXME: HACK: 隐藏 /customer 菜单, 需要一个通用的解决方案,在嵌入的时候就决定是否是私有的
followersOnly: c.component === "did-comments"
// 是否开启仅粉丝可查看的功能,目前只对 discuss kit 开启
// icon: x.icon,
};
}).filter((c) => o || !c.isPrivate);
}, [q, n.data, g?.data, x, G, o]), s = d(() => l.find((e) => le(e.value) === le(v)), [l]), Q = d(() => {
const e = window.blocklet?.appName, p = [s?.label, f("userCenter.title")].filter(Boolean).join("-");
return e ? `${p} | ${e}` : p;
}, [s, f]), be = P((e) => e && (ie(e) ? oe(e, {
...e.props || {},
userCenterTabs: l
}) : Se.map(e, (i) => ie(i) ? oe(i, {
...i.props || {},
userCenterTabs: l
}) : i))), ve = P((e) => {
const i = l.find((p) => p.value === e);
i && (window.location.href = ae(i.url, {
did: o ? void 0 : h
}));
}), K = d(() => /* @__PURE__ */ r(
Ge,
{
user: n.data,
settings: { userCenterTabs: l },
onSave: async (e) => e === "privacy" ? (await g.runAsync(), g.data) : (e === "profile" && await t.refresh(), null),
isMobile: u,
onDestroySelf: ge
}
), [n.data, l, g.data, g.runAsync]), V = d(() => s && s?.value === z, [s]), J = d(() => s && s?.value === S(M, "/profile") || s?.value === T, [s]), we = d(() => s && s?.value === W, [s]), ye = t.useOAuth(), Ce = t.usePasskey(), X = P(() => {
t?.user?.sourceProvider === "passkey" ? Ce.switchPassport(t.user) : ["google", "apple", "email", "github"].includes(t?.user?.sourceProvider ?? "") ? ye.switchOAuthPassport(t.user) : t && t.switchPassport();
}), L = d(() => J ? /* @__PURE__ */ m(
a,
{
sx: {
display: "flex",
flexDirection: "column",
gap: 2.5
},
children: [
o ? /* @__PURE__ */ m(a, { sx: { border: "1px solid", borderColor: "divider", borderRadius: 1.5, p: 2 }, children: [
/* @__PURE__ */ r(
B,
{
sx: {
color: "text.primary",
fontWeight: 600,
mb: 2.5
},
children: f("passport")
}
),
/* @__PURE__ */ r(qe, { user: n.data })
] }) : null,
/* @__PURE__ */ r(Je, { user: n.data })
]
}
) : V && o ? K : we && o ? /* @__PURE__ */ r(Ke, { children: /* @__PURE__ */ r(Ve, {}) }) : null, [V, J, n, o, _, K]), Y = d(() => /* @__PURE__ */ r(
a,
{
sx: {
display: {
xs: o ? "none" : "block",
md: "block"
},
py: 3
},
children: /* @__PURE__ */ r(I, { children: f("emptyContent") })
}
), [o, x]), Z = d(() => !g.data || g.loading ? /* @__PURE__ */ r(
a,
{
sx: {
height: "100%",
minWidth: "160px",
minHeight: "160px",
display: "flex",
justifyContent: "center",
alignItems: "center",
flex: 1
},
children: /* @__PURE__ */ r(Me, {})
}
) : /* @__PURE__ */ r(a, { sx: { flex: 1 }, children: /* @__PURE__ */ r(
Xe,
{
isSupportFollow: w,
currentActiveTab: s,
isMyself: o,
children: b ? /* @__PURE__ */ r(a, { ...H, children: be(b) }) : L
}
) }), [g, s, o, b, H, L, x]), ee = d(() => {
if (n.loading || t.loading)
return null;
if (n.error) {
if (n.error?.response?.status === 404)
return /* @__PURE__ */ r(a, { sx: { width: "100%" }, children: /* @__PURE__ */ r(Ae, { status: 404, description: f("noUserFound") }) });
const p = {
message: n.error.response?.data?.error || n.error.message || "error occurred"
};
return /* @__PURE__ */ r(a, { sx: { width: "100%" }, children: /* @__PURE__ */ r(Ie, { error: p }) });
}
return !h && !n.data ? y || /* @__PURE__ */ r(a, { sx: { width: "100%" }, children: /* @__PURE__ */ m(
a,
{
sx: {
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
gap: 1
},
children: [
/* @__PURE__ */ r(I, { children: f("viewAfterLogin") }),
/* @__PURE__ */ r(We, { size: "small", variant: "contained", onClick: () => t.login(), children: f("loginNow") })
]
}
) }) : h && !n.data && !n.loading ? /* @__PURE__ */ r(I, { style: { width: "100%", paddingTop: 16 }, children: /* @__PURE__ */ m(a, { sx: { textAlign: "center", width: "100%" }, children: [
/* @__PURE__ */ r(B, { variant: "body1", sx: { fontSize: 18, fontWeight: 500 }, children: f("userNotFound") }),
/* @__PURE__ */ r(B, { variant: "body1", color: "text.secondary", children: f("userNotFoundDescription") })
] }) }) : D ? /* @__PURE__ */ m(N, { children: [
l.length > 0 && v ? /* @__PURE__ */ r(
a,
{
sx: {
display: u ? "block" : "flex",
height: "100%",
overflow: "auto",
padding: "1px"
},
children: Z
}
) : null,
l.length === 0 && Y
] }) : C ? /* @__PURE__ */ r(N, { display: "flex", flexDirection: u ? "column" : "row", children: /* @__PURE__ */ r(
de,
{
isMobile: u,
order: u ? 1 : "unset",
isMyself: o,
switchPassport: X,
switchProfile: t.switchProfile,
user: n.data,
showFullDid: !1,
onlyProfile: C,
refreshProfile: R,
isShowSocialActions: w,
sx: {
padding: u ? "16px 0 0 0" : "40px 24px 24px 40px",
...u ? {} : { width: 320, maxWidth: 320, flexShrink: 0 },
boxSizing: "content-box"
}
}
) }) : /* @__PURE__ */ m(N, { display: "flex", flexDirection: u ? "column" : "row", children: [
/* @__PURE__ */ m(
a,
{
className: "user-center-tabs",
sx: {
flex: "1",
order: u ? 2 : "unset",
width: u ? "unset" : "calc(100% - 424px)"
},
children: [
l.length > 0 && v ? /* @__PURE__ */ m(
a,
{
sx: {
display: "flex",
flexDirection: "column",
height: "100%",
overflow: "auto",
padding: "1px"
},
children: [
/* @__PURE__ */ r(
ze,
{
orientation: "horizontal",
variant: "line",
tabs: l,
current: s?.value ?? v,
onChange: ve,
enableTabClick: !0,
sx: {
mb: (e) => `${e.spacing(3)} !important`,
".MuiTabs-flexContainer": {
gap: 3,
".MuiButtonBase-root": {
padding: u ? "16px 4px" : "32px 4px 16px 4px",
fontSize: 16
},
".MuiTab-root": {
display: "block",
textAlign: "left",
alignItems: "flex-start",
justifyContent: "flex-start",
fontWeight: 400,
mr: 0
}
},
".MuiTabs-indicator": {
zIndex: 2
},
".MuiTabs-scroller": {
"&:after": {
content: '""',
display: "block",
position: "sticky",
left: 0,
zIndex: 1,
width: "100%",
height: "1px",
backgroundColor: "divider"
}
}
}
}
),
Z
]
}
) : null,
l.length === 0 && Y
]
}
),
!u && /* @__PURE__ */ r(De, { orientation: "vertical", sx: { ml: 5 } }),
/* @__PURE__ */ r(
de,
{
isMobile: u,
order: u ? 1 : "unset",
isMyself: o,
switchPassport: X,
switchProfile: t.switchProfile,
user: n.data,
refreshProfile: R,
showFullDid: !1,
isShowSocialActions: w,
sx: {
padding: u ? "16px 0 0 0" : "40px 24px 24px 40px",
...u ? {} : { width: 320, maxWidth: 320, flexShrink: 0 },
boxSizing: "content-box"
}
}
)
] });
}, [
n,
l,
o,
s,
g,
v,
_,
L
]), re = d(() => o ? !1 : s?.isPrivate, [o, s]);
if (d(() => C || D || !l.length || !t.user ? !1 : !E && !v && l?.length > 0 || !s || re, [
E,
v,
l,
s,
re,
C,
t.user,
D
])) {
const e = l[0]?.url, i = l.find((p) => p.value === e);
return e && !i?.isPrivate && window.location.replace(
ae(e, {
did: o ? void 0 : h
})
), null;
}
return D || C ? /* @__PURE__ */ m(a, { children: [
/* @__PURE__ */ r(se, { children: /* @__PURE__ */ r("title", { children: Q }) }),
/* @__PURE__ */ r(ue, { style: { display: "none" } }),
/* @__PURE__ */ m(fe, { children: [
/* @__PURE__ */ r(ce, { isMySelf: o, userDid: n.data?.did ?? "", children: ee }),
$
] })
] }) : /* @__PURE__ */ m(
a,
{
sx: {
minHeight: "100vh",
display: "flex",
flexDirection: "column"
},
children: [
/* @__PURE__ */ r(se, { children: /* @__PURE__ */ r("title", { children: Q }) }),
/* @__PURE__ */ r(ue, { bordered: !0, ...he, maxWidth: "100%" }),
/* @__PURE__ */ m(fe, { children: [
/* @__PURE__ */ r(ce, { isMySelf: o, userDid: n.data?.did ?? "", children: ee }),
$
] }),
me ? null : /* @__PURE__ */ r(
_e,
{
bordered: !0,
...xe,
sx: {
".MuiContainer-root": {
maxWidth: 1600
}
}
}
)
]
}
);
}
export {
qr as default
};