UNPKG

@blocklet/ui-react

Version:

Some useful front-end web components that can be used in Blocklets.

503 lines (502 loc) 16.9 kB
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 };