Skip to content

Commit

Permalink
Merge pull request #9508 from hicommonwealth/marcin/9327/contest-screen
Browse files Browse the repository at this point in the history
Contest with decoupled stake
  • Loading branch information
ilijabojanovic authored Oct 10, 2024
2 parents 7f74305 + 0fc5334 commit bcf4421
Show file tree
Hide file tree
Showing 23 changed files with 403 additions and 119 deletions.
2 changes: 1 addition & 1 deletion libs/model/src/community/CreateTopic.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export function CreateTopic(): Command<
throw new InvalidState(Errors.StakeNotAllowed);
}

if (config.CONTESTS.FLAG_FARCASTER_CONTEST) {
if (config.CONTESTS.FLAG_WEIGHTED_TOPICS) {
// new path: stake or ERC20
if (payload.weighted_voting) {
options = {
Expand Down
6 changes: 3 additions & 3 deletions libs/model/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const {
ETH_RPC,
COSMOS_REGISTRY_API,
REACTION_WEIGHT_OVERRIDE,
FLAG_FARCASTER_CONTEST,
FLAG_WEIGHTED_TOPICS,
ALCHEMY_PRIVATE_APP_KEY,
ALCHEMY_PUBLIC_APP_KEY,
MEMBERSHIP_REFRESH_BATCH_SIZE,
Expand Down Expand Up @@ -85,7 +85,7 @@ export const config = configure(
MAX_USER_POSTS_PER_CONTEST: MAX_USER_POSTS_PER_CONTEST
? parseInt(MAX_USER_POSTS_PER_CONTEST, 10)
: 2,
FLAG_FARCASTER_CONTEST: FLAG_FARCASTER_CONTEST === 'true',
FLAG_WEIGHTED_TOPICS: FLAG_WEIGHTED_TOPICS === 'true',
},
AUTH: {
JWT_SECRET: JWT_SECRET || DEFAULTS.JWT_SECRET,
Expand Down Expand Up @@ -183,7 +183,7 @@ export const config = configure(
CONTESTS: z.object({
MIN_USER_ETH: z.number(),
MAX_USER_POSTS_PER_CONTEST: z.number().int(),
FLAG_FARCASTER_CONTEST: z.boolean(),
FLAG_WEIGHTED_TOPICS: z.boolean(),
}),
AUTH: z
.object({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const buildFlag = (env: string | undefined) => {
const featureFlags = {
contest: buildFlag(process.env.FLAG_CONTEST),
contestDev: buildFlag(process.env.FLAG_CONTEST_DEV),
weightedTopics: buildFlag(process.env.FLAG_WEIGHTED_TOPICS),
knockPushNotifications: buildFlag(
process.env.FLAG_KNOCK_PUSH_NOTIFICATIONS_ENABLED,
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ const CommunityNotFoundPage = lazy(

const CommonDomainRoutes = ({
contestEnabled,
farcasterContestEnabled,
weightedTopicsEnabled,
tokenizedCommunityEnabled,
}: RouteFeatureFlags) => [
<Route
Expand Down Expand Up @@ -407,7 +407,7 @@ const CommonDomainRoutes = ({
key="/:scope/manage/topics"
path="/:scope/manage/topics"
element={withLayout(
farcasterContestEnabled ? CommunityTopics : CommunityTopicsOld,
weightedTopicsEnabled ? CommunityTopics : CommunityTopicsOld,
{
scoped: true,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ const ProfilePageRedirect = lazy(() => import('views/pages/profile_redirect'));

const CustomDomainRoutes = ({
contestEnabled,
farcasterContestEnabled,
weightedTopicsEnabled,
tokenizedCommunityEnabled,
}: RouteFeatureFlags) => {
return [
Expand Down Expand Up @@ -307,7 +307,7 @@ const CustomDomainRoutes = ({
key="/manage/topics"
path="/manage/topics"
element={withLayout(
farcasterContestEnabled ? CommunityTopics : CommunityTopicsOld,
weightedTopicsEnabled ? CommunityTopics : CommunityTopicsOld,
{
scoped: true,
},
Expand Down
9 changes: 3 additions & 6 deletions packages/commonwealth/client/scripts/navigation/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,15 @@ import GeneralRoutes from './GeneralRoutes';

export type RouteFeatureFlags = {
contestEnabled: boolean;
farcasterContestEnabled: boolean;
weightedTopicsEnabled: boolean;
tokenizedCommunityEnabled: boolean;
};

const Router = () => {
const client = OpenFeature.getClient();
const contestEnabled = client.getBooleanValue('contest', false);

const farcasterContestEnabled = client.getBooleanValue(
'farcasterContest',
false,
);
const weightedTopicsEnabled = client.getBooleanValue('weightedTopics', false);

const tokenizedCommunityEnabled = client.getBooleanValue(
'tokenizedCommunity',
Expand All @@ -34,7 +31,7 @@ const Router = () => {

const flags = {
contestEnabled,
farcasterContestEnabled,
weightedTopicsEnabled,
tokenizedCommunityEnabled,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ export const NewThreadForm = () => {
);
const isActionAllowedInGatedTopic = !!(memberships || []).find(
(membership) =>
threadTopic.id &&
threadTopic &&
threadTopic?.id &&
membership.topicIds.includes(threadTopic?.id) &&
membership.isAllowed,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from 'shared/analytics/types';
import app from 'state';
import useGetFeeManagerBalanceQuery from 'state/api/communityStake/getFeeManagerBalance';
import { useFetchTopicsQuery } from 'state/api/topics';
import useUserStore from 'state/ui/user';
import Permissions from 'utils/Permissions';
import { useCommunityStake } from 'views/components/CommunityStake';
Expand All @@ -30,6 +31,7 @@ import './AdminContestsPage.scss';

const AdminContestsPage = () => {
const farcasterContestEnabled = useFlag('farcasterContest');
const weightedTopicsEnabled = useFlag('weightedTopics');
const [contestView, setContestView] = useState<ContestView>(ContestView.List);

const navigate = useCommonNavigate();
Expand All @@ -41,6 +43,7 @@ const AdminContestsPage = () => {
const ethChainId = app?.chain?.meta?.ChainNode?.eth_chain_id || 0;
const { stakeData } = useCommunityStake();
const namespace = stakeData?.Community?.namespace;
const communityId = app.activeChainId() || '';

const { trackAnalytics } = useBrowserAnalyticsTrack<BaseMixpanelPayload>({
onAction: true,
Expand All @@ -53,11 +56,23 @@ const AdminContestsPage = () => {
isContestDataLoading,
} = useCommunityContests();

const { data: topicData } = useFetchTopicsQuery({
communityId,
apiEnabled: !!communityId,
});

const hasAtLeastOneWeightedVotingTopic = topicData?.some(
(t) => t.weightedVoting,
);

const { data: feeManagerBalance, isLoading: isFeeManagerBalanceLoading } =
useGetFeeManagerBalanceQuery({
ethChainId: ethChainId!,
namespace,
apiEnabled: !!ethChainId && !!namespace && stakeEnabled,
apiEnabled:
!!ethChainId && !!namespace && weightedTopicsEnabled
? true
: stakeEnabled,
});

const handleCreateContestClicked = () => {
Expand All @@ -76,21 +91,27 @@ const AdminContestsPage = () => {
}

const showBanner =
stakeEnabled && isContestAvailable && ethChainId && namespace;
(weightedTopicsEnabled ? hasAtLeastOneWeightedVotingTopic : stakeEnabled) &&
isContestAvailable &&
ethChainId &&
namespace;

return (
<CWPageLayout>
<div className="AdminContestsPage">
<div className="admin-header-row">
<CWText type="h2">Contests</CWText>

{stakeEnabled && contestView !== ContestView.TypeSelection && (
<CWButton
iconLeft="plusPhosphor"
label="Create contest"
onClick={handleCreateContestClicked}
/>
)}
{(farcasterContestEnabled
? hasAtLeastOneWeightedVotingTopic
: stakeEnabled) &&
contestView !== ContestView.TypeSelection && (
<CWButton
iconLeft="plusPhosphor"
label="Create contest"
onClick={handleCreateContestClicked}
/>
)}
</div>

{contestView === ContestView.List ? (
Expand All @@ -106,6 +127,7 @@ const AdminContestsPage = () => {
contests={contestsData}
isLoading={isContestDataLoading}
isAdmin={isAdmin}
hasWeightedTopic={!!hasAtLeastOneWeightedVotingTopic}
isContestAvailable={isContestAvailable}
stakeEnabled={stakeEnabled}
feeManagerBalance={feeManagerBalance}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ const ContestCard = ({
)}
</div>
<CWText className="topics">
Topics: {topics.map(({ name: topicName }) => topicName).join(', ')}
Topic: {topics.map(({ name: topicName }) => topicName).join(', ')}
</CWText>

<>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import moment from 'moment';
import React, { useState } from 'react';

import { useFlag } from 'hooks/useFlag';
import { Skeleton } from 'views/components/Skeleton';

import EmptyContestsList from '../EmptyContestsList';
Expand Down Expand Up @@ -42,21 +43,25 @@ interface ContestsListProps {
contests: Contest[];
isAdmin: boolean;
isLoading: boolean;
hasWeightedTopic: boolean;
stakeEnabled: boolean;
isContestAvailable: boolean;
feeManagerBalance?: string;
onSetContestSelectionView?: () => void;
}

const ContestsList = ({
contests,
isAdmin,
isLoading,
hasWeightedTopic,
stakeEnabled,
isContestAvailable,
feeManagerBalance,
onSetContestSelectionView,
}: ContestsListProps) => {
const [fundDrawerContest, setFundDrawerContest] = useState<Contest>();
const weightedTopicsEnabled = useFlag('weightedTopics');

if (isLoading) {
return (
Expand All @@ -71,8 +76,11 @@ const ContestsList = ({
return (
<>
<div className="ContestsList">
{isAdmin && (!stakeEnabled || !isContestAvailable) ? (
{isAdmin &&
((weightedTopicsEnabled ? !hasWeightedTopic : !stakeEnabled) ||
!isContestAvailable) ? (
<EmptyContestsList
hasWeightedTopic={hasWeightedTopic}
isStakeEnabled={stakeEnabled}
isContestAvailable={isContestAvailable}
onSetContestSelectionView={onSetContestSelectionView}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,45 @@ interface EmptyContestsListProps {
isStakeEnabled: boolean;
isContestAvailable: boolean;
onSetContestSelectionView?: () => void;
hasWeightedTopic: boolean;
}

const EmptyContestsList = ({
isStakeEnabled,
isContestAvailable,
onSetContestSelectionView,
hasWeightedTopic,
}: EmptyContestsListProps) => {
const navigate = useCommonNavigate();
const farcasterContestEnabled = useFlag('farcasterContest');
const weightedTopicsEnabled = useFlag('weightedTopics');

return (
<div className="EmptyContestsList">
{!isStakeEnabled ? (
{(weightedTopicsEnabled ? !hasWeightedTopic : !isStakeEnabled) ? (
<EmptyCard
img={shape2Url}
title="You must enable Community Stake"
subtitle="Contests require Community Stake..."
button={{
label: 'Enable Community Stake',
handler: () => navigate('/manage/integrations'),
}}
title={
weightedTopicsEnabled
? 'You must have at least one topic with weighted voting enabled to run contest'
: 'You must enable Community Stake'
}
subtitle={
weightedTopicsEnabled
? 'Setting up a contest just takes a few minutes and can be a huge boost to your community.'
: 'Contests require Community Stake...'
}
button={
weightedTopicsEnabled
? {
label: 'Create a topic',
handler: () => navigate('/manage/topics'),
}
: {
label: 'Enable Community Stake',
handler: () => navigate('/manage/integrations'),
}
}
/>
) : !isContestAvailable ? (
<EmptyCard
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useFlag } from 'hooks/useFlag';
import React, { useState } from 'react';
import app from 'state';
import { useTokenMetadataQuery } from 'state/api/tokens';
Expand All @@ -22,6 +23,7 @@ const ManageContest = ({ contestAddress }: ManageContestProps) => {
const [launchContestStep, setLaunchContestStep] =
useState<LaunchContestStep>('DetailsForm');
const [createdContestAddress, setCreatedContestAddress] = useState('');
const weightedTopicsEnabled = useFlag('weightedTopics');

const user = useUserStore();

Expand All @@ -44,7 +46,7 @@ const ManageContest = ({ contestAddress }: ManageContestProps) => {

if (
!user.isLoggedIn ||
!stakeEnabled ||
(weightedTopicsEnabled ? false : !stakeEnabled) ||
!(Permissions.isSiteAdmin() || Permissions.isCommunityAdmin()) ||
contestNotFound
) {
Expand Down Expand Up @@ -81,7 +83,7 @@ const ManageContest = ({ contestAddress }: ManageContestProps) => {
return (
<ContestLiveStep
createdContestAddress={createdContestAddress}
isFarcasterContest={!!contestFormData?.farcasterContestDuration}
isFarcasterContest={false}
fundingTokenTicker={fundingTokenTicker}
fundingTokenAddress={contestFormData?.fundingTokenAddress || ''}
/>
Expand Down
Loading

0 comments on commit bcf4421

Please sign in to comment.