// import "./styles/UserWidget.less";
import { Avatar, Button, Col, Input, List, Modal, Row, Slider, Tooltip } from "antd";
import { BlockExplorerLink } from "../Components/Links";
import { Callback, IOView, NLView } from "../types";
import { ContentImage } from "../Components/Image";
import { CrossCircle } from "../Components/Icons/CrossCircle";
import { DAO } from "../Components/Icons/DAO";
import { DataRow } from "../Components/DataRow";
import { Edit } from "../Components/Icons/Edit";
import { HashDisplay } from "../Components/CryptoEntities";
import { IBadge } from "../hooks/useBadges";
import { ItemGrid } from "../Components/ItemGrid";
import { Link, useHistory, useParams } from "react-router-dom";
import { NewcoinRecept } from "../Components/Recepts";
import { Polygon } from "../Components/Icons/Polygon";
import { PowerupsCacheItem } from "../overmind/api/state";
import { ProgressButton } from "../Components/ProgressButton";
import { RevealInfo } from "../Components/RevealInfo";
import { STAKE_STEPS, STAKE_STEPS_TYPE } from "../overmind/flows/stake/state";
import { ScrollMenu } from "react-horizontal-scrolling-menu";
import { Smallinfo } from "../Components/Icons/Smallinfo";
import { SocialLink } from "../Components/SocialLink";
import { UserFlowRoutes } from "../Pages/User/User";
import { UserReadPrivateResponse, UserReadPublicResponse } from "@newstackdev/iosdk-newgraph-client-js";
import { UserSocials } from "../Pages/User/interfaces/IUser";
import { VerifiedIcon } from "../Components/Icons/VerifiedIcon";
import { showPopUp } from "../utils/popup";
import { useActions, useAppState } from "../overmind";
import { useCachedDaoProposals } from "../hooks/useCached";
import { useCachedPool, useCachedPowerups, useCachedUser } from "../hooks/useCached";
import { useEffect, useState } from "react";
import { useVerified } from "../hooks/useVerified";
import BadgeWidget from "./BadgeWidget";
import CountUp from "react-countup";
import Paragraph from "antd/lib/typography/Paragraph";
import PowerupDialog from "../Components/PowerupDialog";
import ShowMoreText from "react-show-more-text";
import isFinite from "lodash/isFinite";
import usePreventBodyScroll from "../hooks/usePreventBodyScroll";
const ellipsisStyle = {
maxWidth: 125,
whiteSpace: "nowrap",
textOverflow: "ellipsis",
overflow: "hidden",
} as const;
export const SOCIAL_MEDIA = [
UserSocials.SOUNDCLOUD,
UserSocials.INSTAGRAM,
UserSocials.TWITTER,
UserSocials.FACEBOOK,
UserSocials.PINTEREST,
UserSocials.TUMBLR,
UserSocials.YOUTUBE,
UserSocials.DISCORD,
];
export const UserWidgetVertical: NLView<{ user?: UserReadPublicResponse }> = ({ user }) => {
const u = useCachedUser({ id: user?.id || "" });
if (!u) return <>>;
return (
Stake on {u.username}
);
};
const round = (v: number) => Math.round(v * 1000) / 1000;
/**
* User stake widget.
* @param
* @returns
*/
export const UserStake: NLView<{
user?: UserReadPrivateResponse;
mode?: STAKE_STEPS_TYPE;
value?: number;
minValue?: number;
hideButton?: boolean;
hideSelect?: boolean;
buttonText?: string;
closeOnDone?: boolean;
onDone?: Callback;
onCancel?: Callback;
usePowerupTerminology?: boolean;
stakeInNewsafe?: boolean;
}> = ({
user,
mode,
value,
minValue,
hideButton,
buttonText,
hideSelect,
closeOnDone,
onDone,
onCancel,
usePowerupTerminology = false,
stakeInNewsafe,
}) => {
// const [visible, setVisible] = useState(false);
const actions = useActions();
const poolInfo = useCachedPool({ owner: user?.username, code: user?.newcoinTicker });
const [preStakeValue, setPrestakeValue] = useState(0);
const [_value, setValue] = useState(value || 100);
const [fee, setFee] = useState(0.08 * _value);
const state = useAppState();
const [tx, setTx] = useState("");
const [_mode, setMode] = useState(mode ?? STAKE_STEPS.DISABLED);
const _user = useCachedUser(user, true);
const balances = state.newcoin.mainPool?.acc_balances || []; //state.newcoin.account?.acc_balances || [];
const ncoBalance = Number((balances[0] || "").replace(/ GNCO$/, ""));
const membershipValue = state.newcoin.pools[poolInfo.code];
const displayMembershipValue = membershipValue;
minValue = minValue || 100;
const stakeDelta = (membershipValue || 0) - (preStakeValue || 0);
const hasDao = !!poolInfo.code; // && /\.(io|nco)$/.test(user?.username || "");
const closeWallet = () =>
actions.flows.userJourney.setFlag({
flag: "walletShown",
value: "",
});
useEffect(() => {
setMode(mode ?? STAKE_STEPS.DISABLED);
}, [mode]);
useEffect(() => {
const m = _mode ?? STAKE_STEPS.DISABLED;
setMode(m);
actions.flows.stake.setLatestMode({ stakingMode: m });
}, [_mode]);
useEffect(() => {
!hasDao && _mode >= 0 && setMode(STAKE_STEPS.NODAO);
}, [hasDao, _mode]);
const updateValue = (v: number) => {
setValue(v);
setFee(round(0.08 * v));
};
const stake = async () => {
setPrestakeValue(membershipValue);
const res = await actions.api.user.stake({
user: _user,
amount: _value + ".0000",
});
const historyItem = [...state.api.cache.stakeHistory].reverse().find((h) => h.user.username === user?.username);
const success = !!res.TxID_stakePool; //historyItem && !historyItem.error;
success && setTx(res.TxID_stakePool);
setMode(success && closeOnDone ? STAKE_STEPS.DISABLED : STAKE_STEPS.DONE);
};
const startStaking = () => {
setMode(STAKE_STEPS.SELECT);
};
return (
<>
}
// getContainer={getContainer}
visible={_mode == STAKE_STEPS.NODAO}
cancelText="Ok"
// onCancel={() => setMode(STAKE_STEPS.SELECT)}
onCancel={() => {
setMode(STAKE_STEPS.DISABLED);
onDone && onDone({});
}}
okButtonProps={{ style: { display: "none" } }}
wrapClassName="iosdk-modal iosdk-stake-modal"
className="iosdk-modal iosdk-stake-modal nl-white-box-modal"
>
} />
{_user.username}
has not created their DAO yet.
Please check this profile later.
stake()}
closeIcon={ }
onCancel={() => {
setMode(hideButton ? STAKE_STEPS.DISABLED : STAKE_STEPS.SELECT);
}}
footer={false}
className="nl-white-box-modal primary-buttons-modal"
>
} />
{membershipValue > 0 ? (
{/* Join {_user?.username || ""}'s DAO */}
Your membership in {poolInfo.owner.toUpperCase()} DAO is at {displayMembershipValue}. Stake {_value} GNCO more to
increase your membership value.
) : (
Join {_user?.username || ""}'s DAO
)}
Are you sure you want to
{membershipValue ? (
<>
{" "}
increase your stake in {_user?.username || ""}'s DAO by {_value} $GNCO
>
) : (
<>
{" "}
stake {_value} $GNCO to join {_user?.username || ""}
's DAO?
>
)}
?
You will deposit {_value} $GNCO and pay a {round(fee)} $GNCO fee.
{/* to get
your 1000 ${(_user?.username || "").toUpperCase()}. */}
{
stake();
}}
>
Confirm
This is only on Testnet! Need help?
Join our telegram group!
id
= STAKE_STEPS.SELECT && !hideSelect}
okText={"Close"}
footer={false}
onCancel={() => {
_mode === STAKE_STEPS.DONE ? onDone && onDone() : onCancel && onCancel();
setMode(STAKE_STEPS.DISABLED);
}}
className="nl-white-box-modal"
closeIcon={ }
>
} />
{membershipValue > 0 ? (
<>
Your {usePowerupTerminology ? "powerup" : "stake"} in {poolInfo.code || ""} is ${displayMembershipValue} $
{poolInfo.owner.toUpperCase()}. {usePowerupTerminology ? "Powerup" : "Stake"} {_value} GNCO more to increase
your membership value.
>
) : (
<>Join {_user?.username || ""}'s DAO>
)}
setValue(Number(e.target.value))} value={_value} suffix="$GNCO" className="gnco_input" />
{
setMode(STAKE_STEPS.CONFIRM);
}}
>
{buttonText || "Stake"}
{Math.round(fee * 100) / 100} $GNCO Fee
This is only on Testnet! Need help?
Join our telegram group!
{/* Test modal */}
{
setMode(STAKE_STEPS.DISABLED);
onDone &&
onDone({
preStakeValue,
stakeValue: _value,
stakeDelta,
});
}}
>
Congratulations
{preStakeValue ? (
<>
Your stake in {_user?.username}'s DAO increased by {stakeDelta} {poolInfo.code}.
>
) : (
<>You are now a member of the {_user?.username}'s DAO with all the rights and duties associated.>
)}
{_value} $GNCO
— {round((fee * 5) / 8)} $GNCO (5%) creator fee
— {round((fee * 3) / 8)} $GNCO (3%) DAO fee
{round(_value - fee)} $GNCO
{hideButton ? (
""
) : stakeInNewsafe ? (
{
e.preventDefault();
e.stopPropagation();
showPopUp(
`https://auth${
state.config.env.env == "dev" ? "-dev" : ""
}.newsafe.org/swap/GNCO/${user?.newcoinTicker?.toUpperCase()}`,
"__NEWSAFE__",
);
}}
>
{buttonText || "Stake"}
) : (
{
closeWallet();
startStaking();
}}
progressText="Staking..."
type="primary"
>
{buttonText || "Stake"}
)}
>
);
};
export const UserPowerup: NLView<{ user?: UserReadPrivateResponse }> = ({ user }) => {
const [visible, setVisible] = useState(false);
const actions = useActions();
const state = useAppState();
const history = useHistory();
const { verifiedUsers } = useVerified([user?.username || ""]);
const isUserVerified = verifiedUsers && user?.username && verifiedUsers.includes(user.username);
const [stakeMode, setStakeMode] = useState(false);
const currentUserPowerups: PowerupsCacheItem = useCachedPowerups() as any;
const poolInfo = useCachedPool({ owner: user?.username });
const membershipValue = state.newcoin.pools[poolInfo.code];
const rating = currentUserPowerups?.out?.value?.find((u) => u.id === user?.id);
const isPowering = !!rating;
const timeSince = rating?.rating?.created ? Date.now() - new Date(rating?.rating?.created).getDate() : -1;
const powerup = async () => {
setVisible(true);
!isPowering && user && (await actions.api.user.powerup({ user, amount: 1 }));
};
const toStakeMode = () => {
setStakeMode(true);
// setVisible(false);
};
useEffect(() => {
if (!visible) setStakeMode(false);
}, [visible]);
const myProfileUrl = `/user/${state.api.auth.user?.username}`;
// () => actions.routing.historyPush({ location: `/user/stake/${u.id}` })
return (
<>
setVisible(false)}
onCancel={() => setVisible(false)}
cancelButtonProps={{ hidden: true }}
footer={false}
className="iosdk-modal nl-white-box-modal"
closeIcon={ }
>
} />
{isPowering && timeSince > 60000
? "You powered"
: state.indicators.specific["api.user.powerup"]
? "Powering..."
: ""}
{user?.username}
{isUserVerified && }
+1
Multiply your power up
{}}>
8X Power up
{membershipValue ? "∞ Stake more" : "Join the DAO"}
This is only on Testnet! Need help?
Join our telegram group!
Power up
{/* {myProfileUrl === history.location.pathname && (
history.push("/user/invite", {})}
className="primary-green-btn"
>
Invite a friend
)} */}
setStakeMode(false)}
onDone={() => {
setVisible(false);
setStakeMode(false);
}}
hideButton={true}
user={user}
mode={stakeMode ? STAKE_STEPS.SELECT : STAKE_STEPS.DISABLED}
/>
>
);
};
export const UserWidgetTopFixed: NLView<{ user?: UserReadPrivateResponse }> = ({ user }) => {
return (
);
};
export const UserWidgetHeading: NLView<{
user?: UserReadPrivateResponse;
setActiveKey?: React.Dispatch>;
setShowSocials?: React.Dispatch>;
activeKey?: UserFlowRoutes;
newPowerup?: boolean;
hideNewlifeSpecificInfo?: boolean;
disableBadges?: boolean;
isBadgesLoading?: boolean;
badgesError?: string;
badges?: IBadge[];
}> = ({
user,
setActiveKey,
newPowerup = true,
hideNewlifeSpecificInfo = false,
disableBadges,
isBadgesLoading,
badgesError,
badges,
}) => {
const u = useCachedUser({ username: user?.username }, true);
const state = useAppState();
const actions = useActions();
const params = useParams<{ username: string; id: string }>();
const { verifiedUsers } = useVerified([user?.username || ""]);
const isUserVerified = verifiedUsers && u.username && verifiedUsers.includes(u.username);
const poolInfo = useCachedPool({ owner: user?.username });
const daoOwner = params.username || state.config.settings.newcoin.daoDomain;
const daoProposals = useCachedDaoProposals({ daoOwner });
if (!user) return <>>;
const toMonthName = (monthNumber: number) => {
const date = new Date();
date.setMonth(monthNumber - 1);
return date.toLocaleString("en-US", {
month: "long",
});
};
const getSortedSocialMediaIcons = () => {
const sortedSocials = [...SOCIAL_MEDIA].sort((a, b) => {
if (user.verifiedSocialIds?.includes(a)) {
return -1;
}
return 0;
});
return sortedSocials.map((social) => );
};
const monthNumber = new Date(user.created || "").getMonth();
const fullYear = new Date(user.created || "").getFullYear();
const joinedDate = "Joined " + toMonthName(monthNumber) + " " + fullYear;
const isCurrentUserProfile = u.id === state.api.auth.user?.id;
return (
setActiveKey && setActiveKey("Folders")} style={{ cursor: "pointer" }}>
} style={{ width: "160px", height: "160px" }} />
setActiveKey && setActiveKey("Folders")} style={{ cursor: "pointer" }}>
{u.username}
{isUserVerified && }
{isCurrentUserProfile && (
)}
{user.displayName}
{getSortedSocialMediaIcons()}
Show more}
less={Show less }
className="content-css"
anchorClass="my-anchor-css-class"
expanded={false}
width={280}
truncatedEndingComponent={" "}
>
{user.description}
{joinedDate}
setActiveKey && setActiveKey("UserDetail")} className="user-widget-heading__powerup-number">
{/**remove when interface has been updated */}
{/**@ts-ignore*/}
Watts
setActiveKey && setActiveKey("UserDetail")}
className="user-widget-heading__powerup-number u-margin-right-small"
>
{!disableBadges && (
)}
{newPowerup ? : }
{(daoProposals.dao_id || isCurrentUserProfile) && !hideNewlifeSpecificInfo && (
{
if (daoProposals.dao_id) {
actions.routing.historyPush({
location: "/dao/" + user?.username,
});
} else if (isCurrentUserProfile) {
actions.routing.historyPush({ location: "/dao/create" });
}
}}
className="user-widget-heading-details-btn"
>
)}
);
};
export const UserSocialInfo: NLView<{ user?: UserReadPrivateResponse }> = ({ user }) => (
(user as any)[k])}
renderItem={(k) => {
return (
}
/>
);
}}
/>
);
export const UsersList: NLView<{
users?: UserReadPrivateResponse[];
powerUp?: boolean;
title?: string;
layout?: "horizontal" | "vertical";
}> = ({ users, powerUp, title, layout }) => (
<>
{title ? {title} : ""}
{
return (
} />}
description={
{u.username}
{u.powered || ""}
}
/>
);
}}
/>
>
);
// // header="Activity Stream"
// items={users || []}
// render={(u: UserReadPublicResponse) => {
const sliderStyle = {
height: "160px",
color: "#fff",
lineHeight: "160px",
background: "#364d79",
padding: 12,
width: "min(100%,300px)",
};
export const UsersHorizontalScroller: NLView<{
users?: UserReadPrivateResponse[];
powerUp?: boolean;
title?: string;
layout?: "horizontal" | "vertical";
}> = ({ users, powerUp, title, layout }) => {
const { disableScroll, enableScroll } = usePreventBodyScroll();
return (
{title ?
{title} : ""}
} RightArrow={
}
>
{/*
*/}
{users?.map((u, i) => {
return (
} />
{u.username}
{u.powered || ""}
);
}) || <>>}
{/*
*/}
);
};
export const UsersGrid: NLView<{
users?: UserReadPrivateResponse[];
powerUp?: boolean;
title?: string;
layout?: "horizontal" | "vertical";
}> = ({ users, powerUp, title, layout }) => (
<>
{title ? {title} : ""}
{
return (
} />
{u.username}
{u.powered || ""}
);
}}
/>
>
);
export const UserSocialInfoRow: NLView<{ user?: UserReadPrivateResponse }> = ({ user }) => (
<>
{"instagram,soundcloud,twitter,facebook,pinterest,tumblr" //,phone,status"
.split(/,/)
.filter((k) => (user as any)[k])
.map((k) => (
))}
>
);
export const PoolInfoDataRow: NLView<{
pool?: { code: string };
verifyIconLight?: boolean;
noLink?: boolean;
stakeInNewsafe?: boolean;
}> = ({ pool, verifyIconLight = false, noLink, stakeInNewsafe }) => {
const poolInfo = useCachedPool(pool);
const myPools = useAppState().newcoin.pools;
const user = useCachedUser({ username: poolInfo.owner });
const { verifiedUsers } = useVerified([user.username || ""]);
const isUserVerified = verifiedUsers && user.username && verifiedUsers.includes(user.username);
const state = useAppState();
const row = (
} className="avatar-image-small" />
{user.username}
{isUserVerified ? (
verifyIconLight ? (
) : (
)
) : (
false
)}
${poolInfo.code?.toUpperCase()}
{~~myPools[poolInfo?.code]}
TVL: {poolInfo.total.quantity}
{/* {Math.round(Number(poolInfo?.total.quantity.toString().replace(/NCO/, "")))} */}
);
return noLink ? <>{row}> : {row};
//
//
// {pool?.code} ${myPools[poolInfo?.code]} ${poolInfo?.code}
// / ${poolInfo?.total.quantity }
//
// {poolInfo?.owner}
//
// }
// value={
// `${pool?.code} ${myPools[poolInfo?.code]} ${poolInfo?.code
// }
// / ${poolInfo?.total.quantity
// }`}
// link={`/user/${poolInfo?.owner}`}
// target=""
// />
// );
// <>${poolInfo?.owner} {JSON.stringify(poolInfo)}>;
};
export const UserNewcoinPoolsParticipation: IOView<{
user?: UserReadPrivateResponse;
onStakeStart?: Callback;
isWalletUsage?: boolean;
}> = ({ user = {}, onStakeStart, isWalletUsage = false }) => {
const nc = useAppState().newcoin;
return (
<>
Your DAO Memberships
{Object.keys(nc.pools).map(
(code) => (
),
// }
// value={`${val as string} ${code}`}
// />
)}
>
);
};
export const UserNewcoinInfo: NLView<{ user?: UserReadPrivateResponse }> = ({ user = {} }) => {
const state = useAppState();
const { verifiedUsers } = useVerified([user.username || ""]);
const isUserVerified = verifiedUsers && user.username && verifiedUsers.includes(user.username);
const poolInfo = useCachedPool({ owner: user?.username });
return (
<>
{user.username}
) : (
user.username
)
}
link={`https://explorer-dev.newcoin.org/account/${user.username}`}
collapse={true}
/>
} collapse={true} />
} collapse={true} />
}
collapse={true}
/>
}
collapse={true}
/>
>
);
};
export const UserPrivateInfo: NLView<{ user?: UserReadPrivateResponse }> = ({ user }) => (
<>
{user &&
"instagram,soundcloud,twitter,facebook,pinterest,phone,status"
.split(/,/)
.filter((k) => (user as any)[k])
.map((k) => {
return (
{user.firstName} {user.lastName} {user.fullName}
);
})}
>
);