From 6119827cd500120f34c15da0f89b2c29723636aa Mon Sep 17 00:00:00 2001 From: "e-peirong.li" Date: Wed, 26 Mar 2025 21:58:08 +0800 Subject: [PATCH 1/2] feat: change NFC list style of profile --- src/domain/profile/repository.js | 7 +++++ .../individual-profile/IndividualProfile.js | 8 +++--- .../individual-profile/style.module.scss | 26 +++++++++++++++++++ .../profile/widgets/social-info/SocialInfo.js | 7 +++++ ...tationItem.js => GainedReputationItem.tsx} | 25 +++++++++++++----- .../GainedReputationList.js | 6 +++-- 6 files changed, 67 insertions(+), 12 deletions(-) create mode 100644 src/domain/profile/views/individual-profile/style.module.scss rename src/domain/reputation/views/gained-reputation-list/{GainedReputationItem.js => GainedReputationItem.tsx} (54%) diff --git a/src/domain/profile/repository.js b/src/domain/profile/repository.js index f224cf6c..5974109a 100644 --- a/src/domain/profile/repository.js +++ b/src/domain/profile/repository.js @@ -17,6 +17,8 @@ import { unwrapBlockData, wrapBlockData } from '@/components/control/block-editor/helper'; import httpClient from '@/utils/http'; +import { fetchGainedReputationList } from '../reputation/repository'; + async function fetchWeb3BioProfile(address) { return httpClient.get(`https://api.web3.bio/profile/${address}`, { headers: { 'X-API-KEY': process.env.NEXT_PUBLIC_WEB3BIO }, @@ -37,6 +39,11 @@ async function fetchUser(handle) { data.web3Bio = web3BioProfile; } + if (data?.base.user_id) { + const { data: reputation } = await fetchGainedReputationList(data?.base.user_id); + data.reputationList = reputation.list; + } + return { ...others, data, success: true }; } diff --git a/src/domain/profile/views/individual-profile/IndividualProfile.js b/src/domain/profile/views/individual-profile/IndividualProfile.js index d0917889..2c652cac 100644 --- a/src/domain/profile/views/individual-profile/IndividualProfile.js +++ b/src/domain/profile/views/individual-profile/IndividualProfile.js @@ -25,6 +25,7 @@ import SkillOverviewView from '../../../skill/views/skill-overview'; import ActivityTabListWidget from '../../widgets/activity-tab-list'; import SocialInfoWidget from '../../widgets/social-info'; import TabBarWidget from '../../widgets/tab-bar'; +import style from './style.module.scss'; const tabs = [ { @@ -70,12 +71,12 @@ const tabs = [ ]; function IndividualProfileView({ data }) { - const [tabActive, setTabActive] = useState(1); + const [tabActive, setTabActive] = useState(2); const userId = data?.base.user_id; const tabContent = [ , - , + , , ]; @@ -83,11 +84,12 @@ function IndividualProfileView({ data }) {
{tabContent[tabActive]} +
); diff --git a/src/domain/profile/views/individual-profile/style.module.scss b/src/domain/profile/views/individual-profile/style.module.scss new file mode 100644 index 00000000..9b8b8e84 --- /dev/null +++ b/src/domain/profile/views/individual-profile/style.module.scss @@ -0,0 +1,26 @@ +/* + * Copyright 2024 OpenBuild + * + * 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. + */ + +.Tab { + @media (min-width: 768px) { + &:nth-child(1) { + display: none; + } + &:nth-child(2) { + display: none; + } + } +} diff --git a/src/domain/profile/widgets/social-info/SocialInfo.js b/src/domain/profile/widgets/social-info/SocialInfo.js index 14fcbf8c..d7ee378d 100644 --- a/src/domain/profile/widgets/social-info/SocialInfo.js +++ b/src/domain/profile/widgets/social-info/SocialInfo.js @@ -18,6 +18,7 @@ import { useMemo } from 'react'; import { SvgIcon } from '@/components/Image'; +import GainedReputationListView from '../../../reputation/views/gained-reputation-list'; import SocialLink from './SocialLink'; import Web3BioProfile from './Web3BioProfile'; @@ -95,6 +96,12 @@ function SocialInfoWidget({ className, data }) {
)} + {data?.reputationList.length > 0 && ( + <> +

Reputation

+ + + )} {data.base?.user_show_email && data?.social?.user_email !== '' && ( <> diff --git a/src/domain/reputation/views/gained-reputation-list/GainedReputationItem.js b/src/domain/reputation/views/gained-reputation-list/GainedReputationItem.tsx similarity index 54% rename from src/domain/reputation/views/gained-reputation-list/GainedReputationItem.js rename to src/domain/reputation/views/gained-reputation-list/GainedReputationItem.tsx index 50ab47b3..c691dc9a 100644 --- a/src/domain/reputation/views/gained-reputation-list/GainedReputationItem.js +++ b/src/domain/reputation/views/gained-reputation-list/GainedReputationItem.tsx @@ -17,15 +17,26 @@ import Avatar from '@/components/Avatar'; import { formatTime } from '@/utils/date'; -function GainedReputationItem({ data }) { +function GainedReputationItem({ + data, +}: { + data: { + img: string; + title: string; + updated_at: number; + }; +}) { return ( -
-
- + <> + +
+
+ +
+

{data.title}

+

{formatTime(data.updated_at * 1000, 'MMM D, YYYY')}

-

{data.title}

-

{formatTime(data.updated_at * 1000, 'MMM D, YYYY')}

-
+ ); } diff --git a/src/domain/reputation/views/gained-reputation-list/GainedReputationList.js b/src/domain/reputation/views/gained-reputation-list/GainedReputationList.js index 9b90a836..52e8982c 100644 --- a/src/domain/reputation/views/gained-reputation-list/GainedReputationList.js +++ b/src/domain/reputation/views/gained-reputation-list/GainedReputationList.js @@ -23,12 +23,14 @@ import GainedReputationItem from './GainedReputationItem'; function ControlledGainedReputationList({ list }) { return list && list.length > 0 ? ( -
+
{list.map(item => ( ))}
- ) : ; + ) : ( + + ); } function GainedReputationList({ userId }) { From ddd91849060de18ff1a500d0e9b6a7e62b5ed8c0 Mon Sep 17 00:00:00 2001 From: "e-peirong.li" Date: Thu, 27 Mar 2025 22:37:41 +0800 Subject: [PATCH 2/2] refactor: refactor logic of NFT list --- src/domain/profile/repository.js | 9 +-- .../individual-profile/IndividualProfile.js | 3 +- .../individual-profile/style.module.scss | 4 +- .../profile/widgets/social-info/SocialInfo.js | 4 +- .../GainedReputationItem.tsx | 21 ++++--- .../GainedReputationList.js | 62 ------------------- .../GainedReputationList.tsx | 51 +++++++++++++++ 7 files changed, 71 insertions(+), 83 deletions(-) delete mode 100644 src/domain/reputation/views/gained-reputation-list/GainedReputationList.js create mode 100644 src/domain/reputation/views/gained-reputation-list/GainedReputationList.tsx diff --git a/src/domain/profile/repository.js b/src/domain/profile/repository.js index 5974109a..dc4ae662 100644 --- a/src/domain/profile/repository.js +++ b/src/domain/profile/repository.js @@ -39,10 +39,11 @@ async function fetchUser(handle) { data.web3Bio = web3BioProfile; } - if (data?.base.user_id) { - const { data: reputation } = await fetchGainedReputationList(data?.base.user_id); - data.reputationList = reputation.list; - } + const { data: reputation } = await fetchGainedReputationList(data?.base.user_id); + data.extra = { + ...data.extra, + reputationList: reputation.list, + }; return { ...others, data, success: true }; } diff --git a/src/domain/profile/views/individual-profile/IndividualProfile.js b/src/domain/profile/views/individual-profile/IndividualProfile.js index 2c652cac..8f35c752 100644 --- a/src/domain/profile/views/individual-profile/IndividualProfile.js +++ b/src/domain/profile/views/individual-profile/IndividualProfile.js @@ -76,7 +76,7 @@ function IndividualProfileView({ data }) { const tabContent = [ , - , + , , ]; @@ -89,7 +89,6 @@ function IndividualProfileView({ data }) { onChange={setTabActive} /> {tabContent[tabActive]} -
); diff --git a/src/domain/profile/views/individual-profile/style.module.scss b/src/domain/profile/views/individual-profile/style.module.scss index 9b8b8e84..7efd5bda 100644 --- a/src/domain/profile/views/individual-profile/style.module.scss +++ b/src/domain/profile/views/individual-profile/style.module.scss @@ -16,9 +16,7 @@ .Tab { @media (min-width: 768px) { - &:nth-child(1) { - display: none; - } + &:nth-child(1), &:nth-child(2) { display: none; } diff --git a/src/domain/profile/widgets/social-info/SocialInfo.js b/src/domain/profile/widgets/social-info/SocialInfo.js index d7ee378d..244a92ba 100644 --- a/src/domain/profile/widgets/social-info/SocialInfo.js +++ b/src/domain/profile/widgets/social-info/SocialInfo.js @@ -96,10 +96,10 @@ function SocialInfoWidget({ className, data }) {
)} - {data?.reputationList.length > 0 && ( + {data?.extra?.reputationList?.length > 0 && ( <>

Reputation

- + )} diff --git a/src/domain/reputation/views/gained-reputation-list/GainedReputationItem.tsx b/src/domain/reputation/views/gained-reputation-list/GainedReputationItem.tsx index c691dc9a..ac0acc5f 100644 --- a/src/domain/reputation/views/gained-reputation-list/GainedReputationItem.tsx +++ b/src/domain/reputation/views/gained-reputation-list/GainedReputationItem.tsx @@ -19,24 +19,25 @@ import { formatTime } from '@/utils/date'; function GainedReputationItem({ data, + compact = false, }: { data: { img: string; title: string; updated_at: number; }; + compact?: boolean; }) { - return ( - <> - -
-
- -
-

{data.title}

-

{formatTime(data.updated_at * 1000, 'MMM D, YYYY')}

+ return compact ? ( + + ) : ( +
+
+
- +

{data.title}

+

{formatTime(data.updated_at * 1000, 'MMM D, YYYY')}

+
); } diff --git a/src/domain/reputation/views/gained-reputation-list/GainedReputationList.js b/src/domain/reputation/views/gained-reputation-list/GainedReputationList.js deleted file mode 100644 index 52e8982c..00000000 --- a/src/domain/reputation/views/gained-reputation-list/GainedReputationList.js +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright 2024 OpenBuild - * - * 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 { useState, useEffect } from 'react'; - -import { NoData } from '@/components/NoData'; - -import { fetchGainedReputationList } from '../../repository'; -import GainedReputationItem from './GainedReputationItem'; - -function ControlledGainedReputationList({ list }) { - return list && list.length > 0 ? ( -
- {list.map(item => ( - - ))} -
- ) : ( - - ); -} - -function GainedReputationList({ userId }) { - const [list, setList] = useState([]); - const [loading, setLoading] = useState(false); - - useEffect(() => { - if (!userId || loading) { - return; - } - - setLoading(true); - fetchGainedReputationList(userId) - .then(res => setList(res.data.list || [])) - .finally(() => setLoading(false)); - }, [userId]); // eslint-disable-line react-hooks/exhaustive-deps - - return ; -} - -function GainedReputationListView({ userId, data }) { - return Array.isArray(data) ? ( - - ) : ( - - ); -} - -export default GainedReputationListView; diff --git a/src/domain/reputation/views/gained-reputation-list/GainedReputationList.tsx b/src/domain/reputation/views/gained-reputation-list/GainedReputationList.tsx new file mode 100644 index 00000000..2d5f5f16 --- /dev/null +++ b/src/domain/reputation/views/gained-reputation-list/GainedReputationList.tsx @@ -0,0 +1,51 @@ +/** + * Copyright 2024 OpenBuild + * + * 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 clsx from 'clsx'; + +import { NoData } from '@/components/NoData'; + +import GainedReputationItem from './GainedReputationItem'; + +function GainedReputationListView({ + data, + compact = false, +}: { + data?: Array<{ + img: string; + title: string; + updated_at: number; + id: string; + }>; + compact?: boolean; +}) { + return data && data.length > 0 ? ( +
+ {data.map(item => ( + + ))} +
+ ) : ( + + ); +} + +export default GainedReputationListView;