Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
80b4977
fix: add judgement
quinn-gaoo Nov 21, 2025
1742ab5
add check judgement entry, #6881
leocs2417 Nov 21, 2025
9f2c6d9
fix: add identity skeleton, #6881
quinn-gaoo Nov 21, 2025
ddd8f7e
default registrar, #6881
leocs2417 Nov 21, 2025
8df2a57
Fix default registrar, #6881
leocs2417 Nov 21, 2025
516eaf9
Merge branch 'main' into identity-judgement
leocs2417 Nov 21, 2025
9af17e0
Modify check button null guard, #6881
leocs2417 Nov 21, 2025
c643457
fix: replace anchor tags with Link component for navigation, #6881
quinn-gaoo Nov 21, 2025
9fb9973
feat: add verification logic and timer for Discord and Twitter accoun…
quinn-gaoo Nov 24, 2025
840db8a
remove useless code
leocs2417 Nov 24, 2025
1082fda
Implement discord verification, #6881 (#7072)
hyifeng Jan 6, 2026
cbd06ad
Implement twitter authentication, #6881 (#7074)
hyifeng Jan 6, 2026
6cf8598
Implement github authentication, #6881 (#7075)
hyifeng Jan 6, 2026
4e55e08
Identity judgement email, #6881 (#7077)
hyifeng Jan 7, 2026
8e10913
Implement judgement summary data, #6881 (#7078)
hyifeng Jan 7, 2026
283abbc
refactor judgement summary, #6881
hyifeng Jan 7, 2026
efc6e26
Merge branch 'main' into identity-judgement
hyifeng Jan 7, 2026
4bf78a0
Implement non-login page, #6881 (#7079)
hyifeng Jan 7, 2026
bc21432
fix: judgement summary loading, #6881
hyifeng Jan 8, 2026
1067495
Add identity element verification, #6881 (#7092)
hyifeng Jan 9, 2026
2a5aa7a
Improve button tooltip, #6881
hyifeng Jan 12, 2026
c4b6d21
Improve button tooltip, #6881
hyifeng Jan 12, 2026
f8cdef8
Merge branch 'main' into identity-judgement
hyifeng Jan 13, 2026
7832c50
fix: should subscribe to people chain identity if it has a people cha…
hyifeng Jan 13, 2026
6845fb5
fix: missing api param on fetchIdentityOf call, #6881
hyifeng Jan 14, 2026
fd0c054
fix: add people check on Page, #6881
hyifeng Jan 14, 2026
d123194
Identity judgement overview, #6881 (#7108)
hyifeng Jan 15, 2026
7682bf3
Refactor identity prompts, #6881 (#7109)
hyifeng Jan 15, 2026
c92b0d1
Add judgement requests admin page, #6881 (#7111)
hyifeng Jan 15, 2026
55a25da
Merge branch 'main' into identity-judgement
hyifeng Jan 21, 2026
9934ba8
Use new api to get user's judgement request, #6881
hyifeng Jan 21, 2026
82aeeb3
Improve API url, #6881
hyifeng Jan 21, 2026
e468800
fix
hyifeng Jan 22, 2026
b3713f5
Rename verification to verifications, #6881
hyifeng Jan 22, 2026
f2d4166
Rename auth routes, #6881
hyifeng Jan 22, 2026
43a8a36
fix, #6881
hyifeng Jan 22, 2026
1cfc49a
Improve UI style and fix data refresh issue
hyifeng Jan 29, 2026
09558f3
Merge branch 'main' into identity-judgement
wliyongfeng Jan 29, 2026
aec2e33
Improve people menu and rename page routes (#7183)
hyifeng Jan 30, 2026
37751ac
Re-sort prompt and update prompt color, #7183
hyifeng Jan 30, 2026
9e16f33
Hide the verify button when account connected, #7183
hyifeng Jan 30, 2026
1432e3f
Update prompt message text, #7183
hyifeng Jan 30, 2026
294d4f1
Merge branch 'main' into identity-judgement
hyifeng Jan 30, 2026
749625a
fix: identity not shown, #6881
hyifeng Jan 30, 2026
96e0533
Update prompt message text, #6881
hyifeng Jan 30, 2026
ee7e19e
feat: add verification done notification to judgement summary, #6881
hyifeng Jan 30, 2026
8a5ebe7
Merge branch 'main' into identity-judgement
hyifeng Feb 2, 2026
0fa2915
fix empty judgement verifications page, #6881
hyifeng Feb 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion packages/next-common/components/nav/menu/item/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import NavMenuDivider from "../../divider";
import { useNavSubmenuVisible } from "next-common/context/nav";

export default function NavMenuItem({ collapsed, ...menu } = {}) {
const { type, items } = menu || {};
const { type, items, visible = true } = menu || {};
const router = useRouter();
const routePathname = router.asPath.split("?")[0];
const [navSubmenuVisible, setNavSubmenuVisible] = useNavSubmenuVisible();
Expand All @@ -14,6 +14,10 @@ export default function NavMenuItem({ collapsed, ...menu } = {}) {
return <NavMenuDivider />;
}

if (visible === false) {
return null;
}

if (items?.length && !menu?.hideItemsOnMenu) {
return (
<NavMenuItemGroup
Expand Down
5 changes: 5 additions & 0 deletions packages/next-common/components/nav/menu/item/item.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,16 @@ export default function NavMenuItemItem({
onClick,
className = "",
hoverTooltipLabel = true,
visible = true,
}) {
const isExternal = isExternalLink(item?.pathname);
const [, setNavMenuType] = useNavMenuType();
const router = useRouter();

if (visible === false) {
return null;
}

if (
item?.type === NAV_MENU_TYPE.subspace ||
item?.type === NAV_MENU_TYPE.archived
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import Avatar from "next-common/components/avatar";
import getIpfsLink from "next-common/utils/env/ipfsEndpoint";
import { AvatarImg } from "next-common/components/user/styled";
import Gravatar from "next-common/components/gravatar";
import AccountPanelJudgementScrollPrompt from "./components/accountPanelJudgementScrollPrompt";

const ParaChainTeleportPopup = dynamic(() =>
import("next-common/components/paraChainTeleportPopup").then(
Expand Down Expand Up @@ -313,6 +314,7 @@ export default function AccountInfoPanel() {
<Divider />
<AccountBalances />
<ExtensionUpdatePrompt />
<AccountPanelJudgementScrollPrompt />
<AccountPanelScrollPrompt />
</NeutralPanel>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { useEffect, useMemo, useRef, useState } from "react";
import { animate } from "framer-motion";
import { useWindowWidthContext } from "next-common/context/windowSize";
import { Fragment } from "react";

const ITEM_HEIGHT = 40;
const MOBILE_ITEM_HEIGHT = 60;
const ITEM_GAP = 4;

export default function ScrollPromptContainer({ components = [] }) {
const wrapperRef = useRef();
const width = useWindowWidthContext();
const isMobile = width < 768;
const [total, setTotal] = useState(0);
const pauseRef = useRef(false);

const pageSize = total > 2 ? 2 : 1;

const wrapperHeight = useMemo(() => {
if (!total) {
return 0;
}
if (isMobile) {
return pageSize * MOBILE_ITEM_HEIGHT + ITEM_GAP * (pageSize - 1);
}
return pageSize * ITEM_HEIGHT + ITEM_GAP * (pageSize - 1);
}, [isMobile, pageSize, total]);

const [random, setRandom] = useState(1);
useEffect(() => {
if (!wrapperRef.current) {
return;
}

const updateTotal = () => {
setTotal(Math.floor(wrapperRef.current.children.length / 3));
};

updateTotal();

const observer = new MutationObserver(updateTotal);
observer.observe(wrapperRef.current, { childList: true });

return () => observer.disconnect();
}, [random]);

const marginTop = useMemo(() => {
if (isMobile) {
return MOBILE_ITEM_HEIGHT + ITEM_GAP;
}
return ITEM_HEIGHT + ITEM_GAP;
}, [isMobile]);

const indexRef = useRef(0);

useEffect(() => {
indexRef.current = 0;
wrapperRef.current?.scrollTo({ top: 0 });

if (total < 2) {
return;
}

const interval = setInterval(() => {
if (pauseRef.current || !wrapperRef.current) {
return;
}

const nextIndex = indexRef.current + 1;
const from = indexRef.current * marginTop;
const to = nextIndex * marginTop;

animate(from, to, {
duration: 1,
onUpdate: (latest) => {
wrapperRef.current?.scrollTo({ top: latest });
},
onComplete: () => {
indexRef.current = nextIndex;
if (indexRef.current >= total) {
indexRef.current -= total;
wrapperRef.current?.scrollTo({ top: indexRef.current * marginTop });
}
},
});
}, 6500);
return () => clearInterval(interval);
}, [marginTop, total]);

return (
<div
ref={wrapperRef}
style={{
height: wrapperHeight + "px",
display: total ? "" : "none",
}}
className=" overflow-y-hidden flex flex-col gap-1"
onMouseEnter={() => (pauseRef.current = true)}
onMouseLeave={() => (pauseRef.current = false)}
>
{[...components, ...components, ...components].map((Item, index) => {
return (
<Fragment key={index}>
<Item
key={`${random}-${index}`}
onClose={() => setRandom(random + 1)}
/>
</Fragment>
);
})}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import ScrollPromptContainer from "./ScrollPromptContainer";
import { JudgementPrompt } from "./judgementPrompt";

const promptComponents = [JudgementPrompt];

export default function AccountPanelJudgementScrollPrompt() {
return <ScrollPromptContainer components={promptComponents} />;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,14 @@ import { AvatarPrompt } from "./useSetAvatarPrompt";
import { IdentityPrompt } from "./useSetIdentityPrompt";
import { MultisigPrompt } from "./useMultisigPrompt";
import AssetsManagePrompt from "./useAssetsManagePrompt";
import { useEffect, useMemo, useRef, useState } from "react";
import { animate } from "framer-motion";
import { useWindowWidthContext } from "next-common/context/windowSize";
import { Fragment } from "react";
import ScrollPromptContainer from "./ScrollPromptContainer";
import AccountUnlockBalancePrompt from "./accountUnlockBalancePrompt";
import VestingUnlockablePrompt from "./vestingUnlockablePrompt";
import NominatorWithdrawUnbondedPrompt from "./nominatorWithdrawUnbondedPrompt";
import NominatorClaimRewardPrompt from "./nominatorClaimRewardPrompt";
import PoolWithdrawUnbondedPrompt from "./poolWithdrawUnbondedPrompt";
import PoolClaimRewardPrompt from "./poolClaimRewardPrompt";

const ITEM_HEIGHT = 40;
const MOBILE_ITEM_HEIGHT = 60;
const ITEM_GAP = 4;

const promptComponents = [
DelegationPrompt,
AvatarPrompt,
Expand All @@ -33,110 +26,5 @@ const promptComponents = [
];

export default function AccountPanelScrollPrompt() {
const wrapperRef = useRef();
const width = useWindowWidthContext();
const isMobile = width < 768;
const [total, setTotal] = useState(0);
const pauseRef = useRef(false);

const pageSize = total > 2 ? 2 : 1;

const wrapperHeight = useMemo(() => {
if (!total) {
return 0;
}
if (isMobile) {
return pageSize * MOBILE_ITEM_HEIGHT + ITEM_GAP * (pageSize - 1);
}
return pageSize * ITEM_HEIGHT + ITEM_GAP * (pageSize - 1);
}, [isMobile, pageSize, total]);

const [random, setRandom] = useState(1);
useEffect(() => {
if (!wrapperRef.current) {
return;
}

const updateTotal = () => {
setTotal(Math.floor(wrapperRef.current.children.length / 3));
};

updateTotal();

const observer = new MutationObserver(updateTotal);
observer.observe(wrapperRef.current, { childList: true });

return () => observer.disconnect();
}, [random]);

const marginTop = useMemo(() => {
if (isMobile) {
return MOBILE_ITEM_HEIGHT + ITEM_GAP;
}
return ITEM_HEIGHT + ITEM_GAP;
}, [isMobile]);

const indexRef = useRef(0);

useEffect(() => {
indexRef.current = 0;
wrapperRef.current?.scrollTo({ top: 0 });

if (total < 2) {
return;
}

const interval = setInterval(() => {
if (pauseRef.current || !wrapperRef.current) {
return;
}

const nextIndex = indexRef.current + 1;
const from = indexRef.current * marginTop;
const to = nextIndex * marginTop;

animate(from, to, {
duration: 1,
onUpdate: (latest) => {
wrapperRef.current?.scrollTo({ top: latest });
},
onComplete: () => {
indexRef.current = nextIndex;
if (indexRef.current >= total) {
indexRef.current -= total;
wrapperRef.current?.scrollTo({ top: indexRef.current * marginTop });
}
},
});
}, 6500);
return () => clearInterval(interval);
}, [marginTop, total]);

return (
<div
ref={wrapperRef}
style={{
height: wrapperHeight + "px",
display: total ? "" : "none",
}}
className=" overflow-y-hidden flex flex-col gap-1"
onMouseEnter={() => (pauseRef.current = true)}
onMouseLeave={() => (pauseRef.current = false)}
>
{[...promptComponents, ...promptComponents, ...promptComponents].map(
(Item, index) => {
return (
<Fragment key={index}>
<Item
key={random}
onClose={() => {
setRandom(random + 1);
}}
/>
</Fragment>
);
},
)}
</div>
);
return <ScrollPromptContainer components={promptComponents} />;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import RequestJudgementPromptItem from "./requestJudgementPromptItem";
import NavigateToJudgementPagePromptItem from "./navigateToJudgementPagePromptItem";
import { useChain } from "next-common/context/chain";
import { isPeopleChain } from "next-common/utils/chain";

export function JudgementPrompt({ onClose }) {
const chain = useChain();

return (
<>
<NavigateToJudgementPagePromptItem onClose={onClose} />
{isPeopleChain(chain) && <RequestJudgementPromptItem onClose={onClose} />}
</>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import Link from "next-common/components/link";
import {
PromptTypes,
ScrollPromptItemWrapper,
} from "next-common/components/scrollPrompt";
import { CACHE_KEY } from "next-common/utils/constants";
import { useCookieValue } from "next-common/utils/hooks/useCookieValue";
import { useMemo } from "react";
import useMyJudgementRequest from "next-common/components/people/hooks/useMyJudgementRequest";

function NavigateToJudgementPagePrompt() {
return (
<div>
Verify your social accounts for identity judgement.&nbsp;
<Link className="underline text14Medium" href="/people/verifications">
Go to Verifications page
</Link>
.
</div>
);
}

function useNavigateToJudgementPagePromptItem() {
const { value: myJudgementRequest } = useMyJudgementRequest();

const needAction =
myJudgementRequest &&
Object.values(myJudgementRequest.verifications).some(
(verified) => verified !== true,
);

const [visible, setVisible] = useCookieValue(
CACHE_KEY.navigateToJudgementPagePrompt,
true,
);

return useMemo(() => {
if (!visible || !needAction) {
return {};
}

return {
key: CACHE_KEY.navigateToJudgementPagePrompt,
message: <NavigateToJudgementPagePrompt />,
type: PromptTypes.WARNING,
close: () => setVisible(false, { expires: 15 }),
};
}, [needAction, setVisible, visible]);
}

export default function NavigateToJudgementPagePromptItem({ onClose }) {
const prompt = useNavigateToJudgementPagePromptItem();

if (!prompt?.message) {
return null;
}

return (
<ScrollPromptItemWrapper
prompt={{
...prompt,
close: () => {
onClose?.();
prompt?.close?.();
},
}}
/>
);
}
Loading